diff --git a/baystation12.dme b/baystation12.dme index d03a9b4d2d2..997c6d0eaf9 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -102,6 +102,7 @@ #define FILE_DIR "code/modules/DetectiveWork" #define FILE_DIR "code/modules/flufftext" #define FILE_DIR "code/modules/food" +#define FILE_DIR "code/modules/maps" #define FILE_DIR "code/modules/mining" #define FILE_DIR "code/modules/mob" #define FILE_DIR "code/modules/mob/dead" @@ -198,6 +199,7 @@ #define FILE_DIR "icons/vending_icons" #define FILE_DIR "interface" #define FILE_DIR "maps" +#define FILE_DIR "maps/RandomZLevels" #define FILE_DIR "sound" #define FILE_DIR "sound/AI" #define FILE_DIR "sound/ambience" @@ -873,6 +875,11 @@ #include "code\modules\food\food.dm" #include "code\modules\food\meat.dm" #include "code\modules\food\recipes_microwave.dm" +#include "code\modules\maps\dmm_suite.dm" +#include "code\modules\maps\randomZlevel.dm" +#include "code\modules\maps\reader.dm" +#include "code\modules\maps\SwapMaps.dm" +#include "code\modules\maps\writer.dm" #include "code\modules\mining\machine_input_output_plates.dm" #include "code\modules\mining\machine_processing.dm" #include "code\modules\mining\machine_stacking.dm" @@ -1149,8 +1156,6 @@ #include "code\WorkInProgress\Cael_Aislinn\Tajara\tajaran.dm" #include "code\WorkInProgress\Cael_Aislinn\Tajara\whisper.dm" #include "code\WorkInProgress\Chinsky\ashtray.dm" -#include "code\WorkInProgress\mapload\dmm_suite.dm" -#include "code\WorkInProgress\mapload\reader.dm" #include "code\WorkInProgress\Mini\ATM.dm" #include "code\WorkInProgress\Mini\atmos_control.dm" #include "code\WorkInProgress\Mini\pipe_heater.dm" diff --git a/code/WorkInProgress/Cael_Aislinn/Tajara/tajaran.dm b/code/WorkInProgress/Cael_Aislinn/Tajara/tajaran.dm index 6e2cac4529c..d07228e056b 100644 --- a/code/WorkInProgress/Cael_Aislinn/Tajara/tajaran.dm +++ b/code/WorkInProgress/Cael_Aislinn/Tajara/tajaran.dm @@ -354,37 +354,8 @@ overlays += image("icon" = 'belt.dmi', "icon_state" = text("[][]", t1, (!( lying ) ? null : "2")), "layer" = MOB_LAYER) belt.screen_loc = ui_belt - if ((wear_mask && !(wear_mask.see_face)) || (head && !(head.see_face))) // can't see the face - if (wear_id) - if (istype(wear_id, /obj/item/weapon/card/id)) - var/obj/item/weapon/card/id/id = wear_id - if (id.registered_name) - name = id.registered_name - else - name = "Unknown" - else if (istype(wear_id, /obj/item/device/pda)) - var/obj/item/device/pda/pda = wear_id - if (pda.owner) - name = pda.owner - else - name = "Unknown" - else - name = "Unknown" - else - if (wear_id) - if (istype(wear_id, /obj/item/weapon/card/id)) - var/obj/item/weapon/card/id/id = wear_id - if (id.registered_name != real_name) - name = "[real_name] (as [id.registered_name])" - - else if (istype(wear_id, /obj/item/device/pda)) - var/obj/item/device/pda/pda = wear_id - if (pda.owner) - if (pda.owner != real_name) - name = "[real_name] (as [pda.owner])" - else - name = real_name + name = get_visible_name() if (wear_id) wear_id.screen_loc = ui_id diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index 59765bcf6d8..c39421ea81c 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -390,398 +390,404 @@ client return html - Topic(href, href_list, hsrc) +//All BYOND links pass through client/Topic() FIRST and are then directed to [hsrc]/Topic() by the ..() call at the end. +client/Topic(href, href_list, hsrc) - if (href_list["Vars"]) - debug_variables(locate(href_list["Vars"])) + //search the href for script injection //This is a temporary measure + if( findtext(href," 512) return //message too long + var/non_whitespace = 0 + for(var/i=1, i<=length(text), i++) + switch(text2ascii(text,i)) + if(62,60,92,47) return //rejects the text if it contains these bad characters: <, >, \ or / + if(127 to 255) return //rejects weird letters like ÿ + if(0 to 31) return //more weird stuff + if(32) //whitespace + else non_whitespace = 1 + if(non_whitespace) return text //only accepts the text if it has some non-spaces + /proc/strip_html_simple(var/t,var/limit=MAX_MESSAGE_LEN) var/list/strip_chars = list("<",">","&","'") t = copytext(t,1,limit) diff --git a/code/defines/world.dm b/code/defines/world.dm index f3fac8f12b6..9a5cf1c6d9d 100644 --- a/code/defines/world.dm +++ b/code/defines/world.dm @@ -6,12 +6,12 @@ world Topic(href, href_list[]) - world << "Received a Topic() call!" - world << "[href]" - for(var/a in href_list) - world << "[a]" - if(href_list["hello"]) - world << "Hello world!" - return "Hello world!" - world << "End of Topic() call." - ..() \ No newline at end of file +// world << "Received a Topic() call!" +// world << "[href]" +// for(var/a in href_list) +// world << "[a]" +// if(href_list["hello"]) +// world << "Hello world!" +// return "Hello world!" +// world << "End of Topic() call." +// ..() diff --git a/code/game/dna.dm b/code/game/dna.dm index 25e0cd8ffa3..96566c54d2e 100644 --- a/code/game/dna.dm +++ b/code/game/dna.dm @@ -758,7 +758,7 @@ // if (!M.client) // for(var/mob/dead/observer/ghost in world) // if(ghost.corpse == M && ghost.client) -// ghost << "Your corpse has been placed into a cloning scanner. Return to your body if you want to be ressurected/cloned! (Verbs -> Ghost -> Re-enter corpse)" +// ghost << "Your corpse has been placed into a cloning scanner. Return to your body if you want to be resurrected/cloned! (Verbs -> Ghost -> Re-enter corpse)" // break del(G) return @@ -853,7 +853,10 @@ /obj/machinery/computer/scan_consolenew/New() ..() spawn(5) - src.connected = locate(/obj/machinery/dna_scannernew, get_step(src, WEST)) + for(dir in list(NORTH,EAST,SOUTH,WEST)) + connected = locate(/obj/machinery/dna_scannernew, get_step(src, dir)) + if(!isnull(connected)) + break spawn(250) src.injectorready = 1 return diff --git a/code/game/gamemodes/gameticker.dm b/code/game/gamemodes/gameticker.dm index d58fc53ff38..9b1785985fb 100644 --- a/code/game/gamemodes/gameticker.dm +++ b/code/game/gamemodes/gameticker.dm @@ -317,7 +317,7 @@ var/datum/roundinfo/roundinfo = new() if (aiPlayer.connected_robots.len) var/robolist = "The AI's loyal minions were: " for(var/mob/living/silicon/robot/robo in aiPlayer.connected_robots) - robolist += "[robo.name][robo.stat?" (Deactivated) (Played by: [robo.key]), ":", (Played by: [robo.key])"]" + robolist += "[robo.name][robo.stat?" (Deactivated) (Played by: [robo.key]), ":" (Played by: [robo.key]), "]" world << "[robolist]" for (var/mob/living/silicon/robot/robo in world) diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index fd090b36c09..91f56fd4f9e 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -234,6 +234,7 @@ synd_mob.equip_if_possible(new /obj/item/ammo_magazine/a12mm(synd_mob), synd_mob.slot_in_backpack) synd_mob.equip_if_possible(new /obj/item/weapon/reagent_containers/pill/cyanide(synd_mob), synd_mob.slot_in_backpack) synd_mob.equip_if_possible(new /obj/item/weapon/gun/projectile/automatic/c20r(synd_mob), synd_mob.slot_belt) + synd_mob.equip_if_possible(new /obj/item/weapon/storage/box/engineer(synd_mob.back), synd_mob.slot_in_backpack) var/datum/organ/external/O = pick(synd_mob.organs) var/obj/item/weapon/implant/dexplosive/E = new/obj/item/weapon/implant/dexplosive(O) O.implant += E diff --git a/code/game/machinery/OpTable.dm b/code/game/machinery/OpTable.dm index 4395fbea8cd..429fe4be8d2 100644 --- a/code/game/machinery/OpTable.dm +++ b/code/game/machinery/OpTable.dm @@ -13,131 +13,135 @@ var/updatesicon = 1 var/obj/machinery/computer/operating/computer = null - var/id = 0.0 - New() - ..() - if(!isnull(id)) - for(var/obj/machinery/computer/operating/O in world) - if(src.id == O.id) - src.computer = O +/obj/machinery/optable/New() + ..() + for(dir in list(NORTH,EAST,SOUTH,WEST)) + computer = locate(/obj/machinery/computer/operating, get_step(src, dir)) + if (!isnull(computer)) + break + spawn(100) + process() - ex_act(severity) - switch(severity) - if(1.0) +/obj/machinery/optable/ex_act(severity) + + switch(severity) + if(1.0) + //SN src = null + del(src) + return + if(2.0) + if (prob(50)) //SN src = null del(src) return - if(2.0) - if (prob(50)) - //SN src = null - del(src) - return - if(3.0) - if (prob(25)) - src.density = 0 - else - return - - blob_act() - if(prob(75)) - del(src) - - hand_p(mob/user as mob) - return src.attack_paw(user) - return - - attack_paw(mob/user as mob) - if ((usr.mutations & HULK)) - usr << text("\blue You destroy the operating table.") - for(var/mob/O in oviewers()) - if ((O.client && !( O.blinded ))) - O << text("\red [usr] destroys the operating table.") - src.density = 0 - del(src) - if (!( locate(/obj/machinery/optable, user.loc) )) - step(user, get_dir(user, src)) - if (user.loc == src.loc) - user.layer = TURF_LAYER - for(var/mob/M in viewers(user, null)) - M.show_message("The monkey hides under the table!", 1) - //Foreach goto(69) - return - - attack_hand(mob/user as mob) - if ((usr.mutations & HULK)) - usr << text("\blue You destroy the table.") - for(var/mob/O in oviewers()) - if ((O.client && !( O.blinded ))) - O << text("\red [usr] destroys the table.") - src.density = 0 - del(src) - return - - CanPass(atom/movable/mover, turf/target, height=0, air_group=0) - if(air_group || (height==0)) return 1 - - if(istype(mover) && mover.checkpass(PASSTABLE)) - return 1 + if(3.0) + if (prob(25)) + src.density = 0 else - return 0 + return - MouseDrop_T(obj/O as obj, mob/user as mob) - if(isrobot(user)) - return - if ((!( istype(O, /obj/item/weapon) ) || user.equipped() != O)) - return - user.drop_item() - if (O.loc != src.loc) - step(O, get_dir(O, src)) - return +/obj/machinery/optable/blob_act() + if(prob(75)) + del(src) - proc/check_victim() - if(locate(/mob/living/carbon, src.loc)) - var/mob/M = locate(/mob/living/carbon, src.loc) - if(M.resting) - victim = M - if(updatesicon) - icon_state = "table2-active" - return 1 - if(victim) - victim.update_clothing() - victim = null - if(updatesicon) - icon_state = "table2-idle" - processing_objects.Remove(src) +/obj/machinery/optable/hand_p(mob/user as mob) + + return src.attack_paw(user) + return + +/obj/machinery/optable/attack_paw(mob/user as mob) + if ((usr.mutations & HULK)) + usr << text("\blue You destroy the operating table.") + for(var/mob/O in oviewers()) + if ((O.client && !( O.blinded ))) + O << text("\red [usr] destroys the operating table.") + src.density = 0 + del(src) + if (!( locate(/obj/machinery/optable, user.loc) )) + step(user, get_dir(user, src)) + if (user.loc == src.loc) + user.layer = TURF_LAYER + for(var/mob/M in viewers(user, null)) + M.show_message("The monkey hides under the table!", 1) + //Foreach goto(69) + return + +/obj/machinery/optable/attack_hand(mob/user as mob) + if ((usr.mutations & HULK)) + usr << text("\blue You destroy the table.") + for(var/mob/O in oviewers()) + if ((O.client && !( O.blinded ))) + O << text("\red [usr] destroys the table.") + src.density = 0 + del(src) + return + +/obj/machinery/optable/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(air_group || (height==0)) return 1 + + if(istype(mover) && mover.checkpass(PASSTABLE)) + return 1 + else return 0 - process() - check_victim() - attackby(obj/item/weapon/W as obj, mob/user as mob) - if(isrobot(user)) - return - if (istype(W, /obj/item/weapon/grab)) - if(ismob(W:affecting)) - var/mob/M = W:affecting - if (M.client) - M.client.perspective = EYE_PERSPECTIVE - M.client.eye = src - M.resting = 1 - M.loc = src.loc - for (var/mob/C in viewers(src)) - C.show_message("\red [M] has been laid on the operating table by [user].", 3) - for(var/obj/O in src) - O.loc = src.loc - src.add_fingerprint(user) - if(updatesicon) - icon_state = "table2-active" - src.victim = M - M.update_clothing() - processing_objects.Add(src) - del(W) - return - user.drop_item() - if(W && W.loc) - W.loc = src.loc +/obj/machinery/optable/MouseDrop_T(obj/O as obj, mob/user as mob) + if(isrobot(user)) return + if ((!( istype(O, /obj/item/weapon) ) || user.equipped() != O)) + return + user.drop_item() + if (O.loc != src.loc) + step(O, get_dir(O, src)) + return + +/obj/machinery/optable/proc/check_victim() + if(locate(/mob/living/carbon, src.loc)) + var/mob/M = locate(/mob/living/carbon, src.loc) + if(M.resting) + victim = M + if(updatesicon) + icon_state = "table2-active" + return 1 + if(victim) + victim.update_clothing() + victim = null + if(updatesicon) + icon_state = "table2-idle" + processing_objects.Remove(src) + return 0 + +/obj/machinery/optable/process() + check_victim() + +/obj/machinery/optable/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(isrobot(user)) + return + if (istype(W, /obj/item/weapon/grab)) + if(ismob(W:affecting)) + var/mob/M = W:affecting + if (M.client) + M.client.perspective = EYE_PERSPECTIVE + M.client.eye = src + M.resting = 1 + M.loc = src.loc + for (var/mob/C in viewers(src)) + C.show_message("\red [M] has been laid on the operating table by [user].", 3) + for(var/obj/O in src) + O.loc = src.loc + src.add_fingerprint(user) + if(updatesicon) + icon_state = "table2-active" + src.victim = M + M.update_clothing() + processing_objects.Add(src) + del(W) + return + user.drop_item() + if(W && W.loc) + W.loc = src.loc + return /obj/machinery/optable/portable name = "mobile operating table" @@ -146,7 +150,6 @@ icon_state = "up" density = 1 anchored = 0 - id = null updatesicon = 0 New() diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 038e89d5568..09b258edff3 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -149,9 +149,9 @@ if(clonename) src.occupant.real_name = clonename + src.occupant.original_name = clonename //we don't want random ghost names should we die again. else src.occupant.real_name = "clone" //No null names!! - src.occupant.original_name = original_name var/datum/mind/clonemind = (locate(mindref) in ticker.minds) diff --git a/code/game/machinery/computer/HolodeckControl.dm b/code/game/machinery/computer/HolodeckControl.dm index 567f10801f9..90233a01222 100644 --- a/code/game/machinery/computer/HolodeckControl.dm +++ b/code/game/machinery/computer/HolodeckControl.dm @@ -34,9 +34,6 @@ dat += "Please ensure that only holographic weapons are used in the holodeck if a combat simulation has been loaded.
" - if(issilicon(user) && !emagged) - dat += "(Override Safety Protocols?)
" - if(emagged) dat += "(Begin Atmospheric Burn Simulation)
" dat += "Ensure the holodeck is empty before testing.
" @@ -46,6 +43,8 @@ dat += "
" dat += "Safety Protocols are DISABLED
" else + if(issilicon(user)) + dat += "(Override Safety Protocols?)
" dat += "
" dat += "Safety Protocols are ENABLED
" @@ -88,16 +87,19 @@ loadProgram(target) else if(href_list["burntest"]) + if(!emagged) return target = locate(/area/holodeck/source_burntest) if(target) loadProgram(target) else if(href_list["wildlifecarp"]) + if(!emagged) return target = locate(/area/holodeck/source_wildlife) if(target) loadProgram(target) else if(href_list["AIoverride"]) + if(!issilicon(usr)) return emagged = 1 src.add_fingerprint(usr) diff --git a/code/game/machinery/computer/Operating.dm b/code/game/machinery/computer/Operating.dm index 52ca6d1471b..75d80376b85 100644 --- a/code/game/machinery/computer/Operating.dm +++ b/code/game/machinery/computer/Operating.dm @@ -5,15 +5,16 @@ desc = "Used to monitor status of people being operated on." icon_state = "operating" circuit = "/obj/item/weapon/circuitboard/operating" - var/mob/living/carbon/human/victim = null - var/obj/machinery/optable/table = null - var/id = 0.0 + var + mob/living/carbon/human/victim = null + obj/machinery/optable/table = null /obj/machinery/computer/operating/New() ..() - for(var/obj/machinery/optable/O in world) - if(src.id == O.id) - src.table = O + for(dir in list(NORTH,EAST,SOUTH,WEST)) + table = locate(/obj/machinery/optable, get_step(src, dir)) + if (!isnull(table)) + break /obj/machinery/computer/operating/attack_ai(mob/user) add_fingerprint(user) @@ -21,12 +22,14 @@ return interact(user) + /obj/machinery/computer/operating/attack_hand(mob/user) add_fingerprint(user) if(stat & (BROKEN|NOPOWER)) return interact(user) + /obj/machinery/computer/operating/proc/interact(mob/user) if ( (get_dist(src, user) > 1 ) || (stat & (BROKEN|NOPOWER)) ) if (!istype(user, /mob/living/silicon)) @@ -43,7 +46,7 @@ Patient Information:

Name: [src.victim.real_name]
-Age: [!isnull(src.victim.age) ? src.victim.age : "Undetermined"]
+Age: [src.victim.age]
Blood Type: [src.victim.dna.b_type]

Health: [src.victim.health]
@@ -51,7 +54,7 @@ Toxins Damage: [src.victim.getToxLoss()]
Fire Damage: [src.victim.getFireLoss()]
Suffocation Damage: [src.victim.getOxyLoss()]
-Patient Status: [src.victim.stat ? "Non-responsive" : "Stable"]
+Patient Status: [src.victim.stat ? "Non-Responsive" : "Stable"]
"} else src.victim = null @@ -63,15 +66,15 @@ user << browse(dat, "window=op") onclose(user, "op") + /obj/machinery/computer/operating/Topic(href, href_list) if(..()) return if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) usr.machine = src -// if (href_list["update"]) -// src.interact(usr) return + /obj/machinery/computer/operating/process() if(!(stat & (NOPOWER|BROKEN)) ) use_power(500) diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm index 8914d5b6ff4..9e79a702fc4 100644 --- a/code/game/machinery/computer/card.dm +++ b/code/game/machinery/computer/card.dm @@ -245,7 +245,9 @@ if (authenticated) var/t1 = href_list["assign_target"] if(t1 == "Custom") - t1 = input("Enter a custom job assignment.","Assignment") + var/temp_t = copytext(sanitize(input("Enter a custom job assignment.","Assignment")),1,MAX_MESSAGE_LEN) + if(temp_t) + t1 = temp_t else modify.access = ( istype(src,/obj/machinery/computer/card/centcom) ? get_centcom_access(t1) : get_access(t1) ) if (modify) diff --git a/code/game/machinery/computer/hologram.dm b/code/game/machinery/computer/hologram.dm index 5539a616f49..278a0704ff8 100644 --- a/code/game/machinery/computer/hologram.dm +++ b/code/game/machinery/computer/hologram.dm @@ -1,3 +1,17 @@ +/obj/machinery/computer/hologram_comp + name = "Hologram Computer" + desc = "Rumoured to control holograms." + icon = 'stationobjs.dmi' + icon_state = "holo_console0" + var + obj/machinery/hologram/projector/projector = null + temp = null + lumens = 0.0 + h_r = 245.0 + h_g = 245.0 + h_b = 245.0 + + /obj/machinery/computer/hologram_comp/New() ..() spawn( 10 ) diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm index 9c9d6c675af..9a02fe6025b 100644 --- a/code/game/machinery/requests_console.dm +++ b/code/game/machinery/requests_console.dm @@ -1,5 +1,5 @@ /******************** Requests Console ********************/ -/** Originally written by errorage, updated by: **/ +/** Originally written by errorage, updated by: Carn, needs more work though. I just added some security fixes */ var/req_console_assistance = list() var/req_console_supplies = list() @@ -41,7 +41,7 @@ var/list/obj/machinery/requests_console/allConsoles = list() // 9 = authentication before sending // 10 = send announcement var/silent = 0 // set to 1 for it not to beep all the time - var/hackState = 0 +// var/hackState = 0 // 0 = not hacked // 1 = hacked var/announcementConsole = 0 @@ -57,270 +57,319 @@ var/list/obj/machinery/requests_console/allConsoles = list() luminosity = 0 /obj/machinery/requests_console/New() - src.name = "[src.department] Requests Console" + name = "[department] Requests Console" allConsoles += src //req_console_departments += department - switch(src.departmentType) + switch(departmentType) if(1) - if(!("[src.department]" in req_console_assistance)) + if(!("[department]" in req_console_assistance)) req_console_assistance += department if(2) - if(!("[src.department]" in req_console_supplies)) + if(!("[department]" in req_console_supplies)) req_console_supplies += department if(3) - if(!("[src.department]" in req_console_information)) + if(!("[department]" in req_console_information)) req_console_information += department if(4) - if(!("[src.department]" in req_console_assistance)) + if(!("[department]" in req_console_assistance)) req_console_assistance += department - if(!("[src.department]" in req_console_supplies)) + if(!("[department]" in req_console_supplies)) req_console_supplies += department if(5) - if(!("[src.department]" in req_console_assistance)) + if(!("[department]" in req_console_assistance)) req_console_assistance += department - if(!("[src.department]" in req_console_information)) + if(!("[department]" in req_console_information)) req_console_information += department if(6) - if(!("[src.department]" in req_console_supplies)) + if(!("[department]" in req_console_supplies)) req_console_supplies += department - if(!("[src.department]" in req_console_information)) + if(!("[department]" in req_console_information)) req_console_information += department if(7) - if(!("[src.department]" in req_console_assistance)) + if(!("[department]" in req_console_assistance)) req_console_assistance += department - if(!("[src.department]" in req_console_supplies)) + if(!("[department]" in req_console_supplies)) req_console_supplies += department - if(!("[src.department]" in req_console_information)) + if(!("[department]" in req_console_information)) req_console_information += department /obj/machinery/requests_console/attack_hand(user as mob) var/dat - dat = text("Requests Console

[src.department] Requests Console

") - if(!src.open) - if (src.screen == 0) - announceAuth = 0 - if (src.newmessagepriority == 1) - dat += text("There are new messages
") - if (src.newmessagepriority == 2) - dat += text("NEW PRIORITY MESSAGES
") - dat += text("View Messages

") + dat = text("Requests Console

[department] Requests Console

") + if(!open) + switch(screen) + if(1) //req. assistance + dat += text("Which department do you need assistance from?

") + for(var/dpt in req_console_assistance) + if (dpt != department) + dat += text("[dpt] (Message or ") + dat += text("High Priority") +// if (hackState == 1) +// dat += text(" or EXTREME)") + dat += text(")
") + dat += text("
Back
") + + if(2) //req. supplies + dat += text("Which department do you need supplies from?

") + for(var/dpt in req_console_supplies) + if (dpt != department) + dat += text("[dpt] (Message or ") + dat += text("High Priority") +// if (hackState == 1) +// dat += text(" or EXTREME)") + dat += text(")
") + dat += text("
Back
") + + if(3) //relay information + dat += text("Which department would you like to send information to?

") + for(var/dpt in req_console_information) + if (dpt != department) + dat += text("[dpt] (Message or ") + dat += text("High Priority") +// if (hackState == 1) +// dat += text(" or EXTREME)") + dat += text(")
") + dat += text("
Back
") + + if(6) //sent successfully + dat += text("Message sent

") + dat += text("Continue
") + + if(7) //unsuccessful; not sent + dat += text("An error occurred.

") + dat += text("Continue
") + + if(8) //view messages + for (var/obj/machinery/requests_console/Console in allConsoles) + if (Console.department == department) + Console.newmessagepriority = 0 + Console.icon_state = "req_comp0" + Console.luminosity = 1 + newmessagepriority = 0 + icon_state = "req_comp0" + for(var/msg in messages) + dat += text("[msg]
") + dat += text("Back to main menu
") + + if(9) //authentication before sending + dat += text("Message Authentication

") + dat += text("Message for [dpt]: [message]

") + dat += text("You may authenticate your message now by scanning your ID or your stamp

") + dat += text("Validated by: [msgVerified]
"); + dat += text("Stamped by: [msgStamped]
"); + dat += text("Send
"); + dat += text("
Back
") + + if(10) //send announcement + dat += text("Station wide announcement

") + if(announceAuth) + dat += text("Authentication accepted

") + else + dat += text("Swipe your card to authenticate yourself.

") + dat += text("Message: [message] Write

") + if (announceAuth && message) + dat += text("Announce
"); + dat += text("
Back
") + + else //main menu + screen = 0 + announceAuth = 0 + if (newmessagepriority == 1) + dat += text("There are new messages
") + if (newmessagepriority == 2) + dat += text("NEW PRIORITY MESSAGES
") + dat += text("View Messages

") + + dat += text("Request Assistance
") + dat += text("Request Supplies
") + dat += text("Relay Anonymous Information

") + if(announcementConsole) + dat += text("Send station-wide announcement

") + if (silent) + dat += text("Speaker OFF") + else + dat += text("Speaker ON") - dat += text("Request Assistance
") - dat += text("Request Supplies
") - dat += text("Relay Anonymous Information

") - if(announcementConsole) - dat += text("Send station-wide announcement

") - //dat += text("
Call Mailman

") // This is the line to call the mailman, it's intended for it to message him on his PDA - if (src.silent) - dat += text("Speaker OFF") - else - dat += text("Speaker ON") - if (src.screen == 1) - dat += text("Which department do you need assistance from?

") - for(var/dpt in req_console_assistance) - if (dpt != src.department) - dat += text("[dpt] (Message or ") - dat += text("High Priority") - if (src.hackState == 1) - dat += text(" or EXTREME)") - dat += text(")
") - dat += text("
Back
") - if (src.screen == 2) - dat += text("Which department do you need supplies from?

") - for(var/dpt in req_console_supplies) - if (dpt != src.department) - dat += text("[dpt] (Message or ") - dat += text("High Priority") - if (src.hackState == 1) - dat += text(" or EXTREME)") - dat += text(")
") - dat += text("
Back
") - if (src.screen == 3) - dat += text("Which department would you like to send information to?

") - for(var/dpt in req_console_information) - if (dpt != src.department) - dat += text("[dpt] (Message or ") - dat += text("High Priority") - if (src.hackState == 1) - dat += text(" or EXTREME)") - dat += text(")
") - dat += text("
Back
") - if (src.screen == 6) - dat += text("Message sent

") - dat += text("Continue
") - if (src.screen == 7) - dat += text("An error occurred.

") - dat += text("Continue
") - if (src.screen == 8) - for (var/obj/machinery/requests_console/CONSOLE in allConsoles) - if (CONSOLE.department == src.department) - CONSOLE.newmessagepriority = 0 - CONSOLE.icon_state = "req_comp0" - CONSOLE.luminosity = 1 - src.newmessagepriority = 0 - icon_state = "req_comp0" - for(var/msg in src.messages) - dat += text("[msg]
") - dat += text("Back to main menu
") - if (src.screen == 9) - dat += text("Message Authentication

") - dat += text("Message for [src.dpt]: [message]

") - dat += text("You may authenticate your message now by scanning your ID or your stamp

") - dat += text("Validated by: [msgVerified]
"); - dat += text("Stamped by: [msgStamped]
"); - dat += text("Send
"); - dat += text("
Back
") - if (src.screen == 10) - dat += text("Station wide announcement

") - if(announceAuth) - dat += text("Authentication accepted

") - else - dat += text("Swipe your card to authenticate yourself.

") - dat += text("Message: [message] Write

") - if (announceAuth && message) - dat += text("Announce
"); - dat += text("
Back
") user << browse("[dat]", "") onclose(user, "req_console") return /obj/machinery/requests_console/Topic(href, href_list) - if(..()) - return + if(..()) return usr.machine = src - src.add_fingerprint(usr) - if(href_list["write"]) - src.dpt = href_list["write"] //write contains the string of the receiving department's name - src.message = strip_html(input(usr, "Write your message", "Messanger", "")) - src.priority = href_list["priority"] - while (findtext(src.message," ") == 1) - src.message = copytext(src.message,2,lentext(src.message)+1) - if (findtext(src.message," ") == 1) - src.message = ""; - if (src.message != "") + add_fingerprint(usr) + + if(reject_bad_text(href_list["write"])) + dpt = ckey(href_list["write"]) //write contains the string of the receiving department's name + + var/new_message = reject_bad_text(input(usr, "Write your message:", "Awaiting Input", "")) + if(new_message) + message = new_message screen = 9 + switch(href_list["priority"]) + if("2") priority = 2 + else priority = -1 else dpt = ""; - msgVerified = ""; - msgStamped = ""; + msgVerified = "" + msgStamped = "" screen = 0 priority = -1 + if(href_list["writeAnnouncement"]) - src.message = input(usr, "Write your message", "Messanger", "") - src.priority = href_list["priority"] - while (findtext(src.message," ") == 1) - src.message = copytext(src.message,2,lentext(src.message)+1) - if (findtext(src.message," ") == 1) - src.message = ""; - if (src.message == "") - announceAuth = 0; + var/new_message = reject_bad_text(input(usr, "Write your message:", "Awaiting Input", "")) + if(new_message) + message = new_message + switch(href_list["priority"]) + if("2") priority = 2 + else priority = -1 + else + message = "" + announceAuth = 0 screen = 0 + if(href_list["sendAnnouncement"]) - world << "[department] announcement: [html_encode(message)]" + if(!announcementConsole) return + world << "[department] announcement: [message]" announceAuth = 0 message = "" screen = 0 - if(href_list["department"] && src.message) - var/log_msg = src.message - var/message = src.message; - message += "
" - if (src.msgVerified) - message += src.msgVerified - message += "
" - if (src.msgStamped) - message += src.msgStamped - message += "
" - src.screen = 7 //if it's successful, this will get overrwritten (7 = unsufccessfull, 6 = successfull) - if (message) + + if( href_list["department"] && message ) + var/log_msg = message + var/sending = message + sending += "
" + if (msgVerified) + sending += msgVerified + sending += "
" + if (msgStamped) + sending += msgStamped + sending += "
" + screen = 7 //if it's successful, this will get overrwritten (7 = unsufccessfull, 6 = successfull) + if (sending) for (var/obj/machinery/message_server/MS in world) - MS.send_rc_message(href_list["department"],src.department,log_msg,msgStamped,msgVerified,priority) - for (var/obj/machinery/requests_console/CONSOLE in allConsoles) - if (ckey(CONSOLE.department) == ckey(href_list["department"])) - if(src.priority == "2") //High priority - if(CONSOLE.newmessagepriority < 2) - CONSOLE.newmessagepriority = 2 - CONSOLE.icon_state = "req_comp2" - if(!CONSOLE.silent) - playsound(CONSOLE.loc, 'twobeep.ogg', 50, 1) - for (var/mob/O in hearers(5, CONSOLE.loc)) - O.show_message(text("\icon[CONSOLE] *The Requests Console beeps: 'PRIORITY Alert in [src.department]'")) - CONSOLE.messages += "High Priority message from [src.department]
[message]" - else if(src.priority == "3" - ) //Not implemanted, but will be - if(CONSOLE.newmessagepriority < 3) - CONSOLE.newmessagepriority = 3 - CONSOLE.icon_state = "req_comp3" - if(!CONSOLE.silent) - playsound(CONSOLE.loc, 'twobeep.ogg', 50, 1) - for (var/mob/O in hearers(7, CONSOLE.loc)) - O.show_message(text("\icon[CONSOLE] *The Requests Console yells: 'EXTREME PRIORITY alert in [src.department]'")) - CONSOLE.messages += "Extreme Priority message from [ckey(src.department)]
[message]" - else // Normal priority - if(CONSOLE.newmessagepriority < 1) - CONSOLE.newmessagepriority = 1 - CONSOLE.icon_state = "req_comp1" - if(!CONSOLE.silent) - playsound(CONSOLE.loc, 'twobeep.ogg', 50, 1) - for (var/mob/O in hearers(4, CONSOLE.loc)) - O.show_message(text("\icon[CONSOLE] *The Requests Console beeps: 'Message from [src.department]'")) - CONSOLE.messages += "Message from [src.department]

[message]" - src.screen = 6 - CONSOLE.luminosity = 2 - src.messages += "Message sent to [src.dpt]
[message]" - if(href_list["setScreen"]) - src.screen = text2num(href_list["setScreen"]) - if (src.screen == 0) - dpt = ""; - msgVerified = ""; - msgStamped = ""; - message = ""; - priority = -1; - if(href_list["setSilent"]) - src.silent = text2num(href_list["setSilent"]) - src.updateUsrDialog() + MS.send_rc_message(href_list["department"],department,log_msg,msgStamped,msgVerified,priority) + + for (var/obj/machinery/requests_console/Console in allConsoles) + if (ckey(Console.department) == ckey(href_list["department"])) + + switch(priority) + if("2") //High priority + if(Console.newmessagepriority < 2) + Console.newmessagepriority = 2 + Console.icon_state = "req_comp2" + if(!Console.silent) + playsound(Console.loc, 'twobeep.ogg', 50, 1) + for (var/mob/O in hearers(5, Console.loc)) + O.show_message(text("\icon[Console] *The Requests Console beeps: 'PRIORITY Alert in [department]'")) + Console.messages += "High Priority message from [department]
[sending]" + + // if("3") //Not implemanted, but will be //Removed as it doesn't look like anybody intends on implimenting it ~Carn + // if(Console.newmessagepriority < 3) + // Console.newmessagepriority = 3 + // Console.icon_state = "req_comp3" + // if(!Console.silent) + // playsound(Console.loc, 'twobeep.ogg', 50, 1) + // for (var/mob/O in hearers(7, Console.loc)) + // O.show_message(text("\icon[Console] *The Requests Console yells: 'EXTREME PRIORITY alert in [department]'")) + // Console.messages += "Extreme Priority message from [ckey(department)]
[message]" + + else // Normal priority + if(Console.newmessagepriority < 1) + Console.newmessagepriority = 1 + Console.icon_state = "req_comp1" + if(!Console.silent) + playsound(Console.loc, 'twobeep.ogg', 50, 1) + for (var/mob/O in hearers(4, Console.loc)) + O.show_message(text("\icon[Console] *The Requests Console beeps: 'Message from [department]'")) + Console.messages += "Message from [department]

[message]" + + screen = 6 + Console.luminosity = 2 + messages += "Message sent to [dpt]
[message]" + + //Handle screen switching + switch(text2num(href_list["setScreen"])) + if(null) //skip + if(1) //req. assistance + screen = 1 + if(2) //req. supplies + screen = 2 + if(3) //relay information + screen = 3 +// if(4) //write message +// screen = 4 + if(5) //choose priority + screen = 5 + if(6) //sent successfully + screen = 6 + if(7) //unsuccessfull; not sent + screen = 7 + if(8) //view messages + screen = 8 + if(9) //authentication + screen = 9 + if(10) //send announcement + if(!announcementConsole) return + screen = 10 + else //main menu + dpt = "" + msgVerified = "" + msgStamped = "" + message = "" + priority = -1 + screen = 0 + + //Handle silencing the console + switch( href_list["setSilent"] ) + if(null) //skip + if("1") silent = 1 + else silent = 0 + + updateUsrDialog() return //err... hacking code, which has no reason for existing... but anyway... it's supposed to unlock priority 3 messanging on that console (EXTREME priority...) the code for that actually exists. /obj/machinery/requests_console/attackby(var/obj/item/weapon/O as obj, var/mob/user as mob) /* if (istype(O, /obj/item/weapon/crowbar)) - if(src.open) - src.open = 0 - src.icon_state="req_comp0" + if(open) + open = 0 + icon_state="req_comp0" else - src.open = 1 - if(src.hackState == 0) - src.icon_state="req_comp_open" - else if(src.hackState == 1) - src.icon_state="req_comp_rewired" + open = 1 + if(hackState == 0) + icon_state="req_comp_open" + else if(hackState == 1) + icon_state="req_comp_rewired" if (istype(O, /obj/item/weapon/screwdriver)) - if(src.open) - if(src.hackState == 0) - src.hackState = 1 - src.icon_state="req_comp_rewired" - else if(src.hackState == 1) - src.hackState = 0 - src.icon_state="req_comp_open" + if(open) + if(hackState == 0) + hackState = 1 + icon_state="req_comp_rewired" + else if(hackState == 1) + hackState = 0 + icon_state="req_comp_open" else user << "You can't do much with that."*/ if (istype(O, /obj/item/weapon/card/id)) - if(src.screen == 9) + if(screen == 9) var/obj/item/weapon/card/id/T = O - src.msgVerified = text("Verified by [T.registered_name] ([T.assignment])") - src.updateUsrDialog() - if(src.screen == 10) + msgVerified = text("Verified by [T.registered_name] ([T.assignment])") + updateUsrDialog() + if(screen == 10) var/obj/item/weapon/card/id/ID = O if (access_RC_announce in ID.access) announceAuth = 1 else announceAuth = 0 user << "\red You are not authorized to send announcements." - src.updateUsrDialog() + updateUsrDialog() if (istype(O, /obj/item/weapon/stamp)) - if(src.screen == 9) + if(screen == 9) var/obj/item/weapon/stamp/T = O - src.msgStamped = text("Stamped with the [T.name]") - src.updateUsrDialog() - return \ No newline at end of file + msgStamped = text("Stamped with the [T.name]") + updateUsrDialog() + return diff --git a/code/game/machinery/telecomms/telecommunications.dm b/code/game/machinery/telecomms/telecommunications.dm index 6e9d41ea4d8..febb82e26bc 100644 --- a/code/game/machinery/telecomms/telecommunications.dm +++ b/code/game/machinery/telecomms/telecommunications.dm @@ -103,11 +103,10 @@ if(machine.is_freq_listening(signal)) machine.traffic++ - spawn() - if(copysig && copy) - machine.receive_information(copy, src) - else - machine.receive_information(signal, src) + if(copysig && copy) + machine.receive_information(copy, src) + else + machine.receive_information(signal, src) if(send_count > 0 && is_freq_listening(signal)) traffic++ diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm index 37f159ef552..1fec2e76069 100644 --- a/code/game/machinery/teleporter.dm +++ b/code/game/machinery/teleporter.dm @@ -56,8 +56,10 @@ for(var/obj/item/device/radio/beacon/R in world) var/turf/T = get_turf(R) - if (!T) continue - if(T.z == 2) continue + if (!T) + continue + if(T.z == 2) + continue var/tmpname = T.loc.name if(areaindex[tmpname]) tmpname = "[tmpname] ([++areaindex[tmpname]])" diff --git a/code/game/machinery/turrets.dm b/code/game/machinery/turrets.dm index bc1c8ffe9c2..893162ccfe3 100644 --- a/code/game/machinery/turrets.dm +++ b/code/game/machinery/turrets.dm @@ -11,6 +11,8 @@ //TODO: make teleporting to places trigger Entered() ~Carn +// Done. + /area/turret_protected/Entered(O) ..() if( master && master != src ) @@ -84,6 +86,7 @@ anchored = 1 layer = 3.5 density = 0 + var/obj/machinery/turret/host = null /obj/machinery/turret/proc/isPopping() return (popping!=0) @@ -157,6 +160,7 @@ return if(src.cover==null) src.cover = new /obj/machinery/turretcover(src.loc) + src.cover.host = src protected_area = get_protected_area() if(!enabled || !protected_area || protected_area.turretTargets.len<=0) if(!isDown() && !isPopping()) diff --git a/code/game/magic/library.dm b/code/game/magic/library.dm index 589b58a120f..e8e3c189b64 100644 --- a/code/game/magic/library.dm +++ b/code/game/magic/library.dm @@ -759,22 +759,19 @@ datum/borrowbook // Datum used to keep track of who has borrowed what when and f B.name = ticker.Bible_name B.deity_name = ticker.Bible_deity_name - bibledelay = 60 - spawn(0) - while(bibledelay >= 1 && src) - sleep(10) - bibledelay -- // subtract one second to countdown - + bibledelay = 1 + spawn(60) bibledelay = 0 else for (var/mob/V in hearers(src)) - V.show_message("[src]'s monitor flashes, \"[bibledelay] seconds remaining until the bible printer is ready for use.\"") + V.show_message("[src]'s monitor flashes, \"Bible printer currently unavailable, please wait a moment.\"") if("7") screenstate = 7 if(href_list["arccheckout"]) - src.arcanecheckout = 1 + if(src.emagged) + src.arcanecheckout = 1 src.screenstate = 0 if(href_list["increasetime"]) checkoutperiod += 1 @@ -865,22 +862,19 @@ datum/borrowbook // Datum used to keep track of who has borrowed what when and f alert("Upload Complete.") if(href_list["targetid"]) - if(!bibledelay)//Taken from the bible code part thing - bibledelay = 60 - spawn(0) - while(bibledelay >= 1 && src) - sleep(10) - bibledelay -- // subtract one second to countdown - - bibledelay = 0 - if(BOOKS_USE_SQL && config.sql_enabled) var/sqlid = href_list["targetid"] var/DBConnection/dbcon = new() dbcon.Connect("dbi:mysql:[sqldb]:[sqladdress]:[sqlport]","[sqllogin]","[sqlpass]") if(!dbcon.IsConnected()) alert("Connection to Archive has been severed. Aborting.") + if(bibledelay) + for (var/mob/V in hearers(src)) + V.show_message("[src]'s monitor flashes, \"Printer unavailable. Please allow a short time before attempting to print.\"") else + bibledelay = 1 + spawn(60) + bibledelay = 0 var/DBQuery/query = dbcon.NewQuery("SELECT * FROM library WHERE id=[sqlid]") query.Execute() diff --git a/code/game/magic/musician.dm b/code/game/magic/musician.dm index 3bb9287e6c0..c46f7464752 100644 --- a/code/game/magic/musician.dm +++ b/code/game/magic/musician.dm @@ -5,9 +5,9 @@ tempo = 5 /obj/structure/device/piano - name = "space piano" + name = "space minimoog" icon = 'musician.dmi' - icon_state = "piano" + icon_state = "minimoog" anchored = 1 density = 1 var @@ -500,7 +500,7 @@ if(href_list["import"]) var/t = "" do - t = input(usr, "Please paste the entire song, formated:", text("[]", src.name), t) as message + t = input(usr, "Please paste the entire song, formatted:", text("[]", src.name), t) as message if (!in_range(src, usr)) return diff --git a/code/game/master_controller.dm b/code/game/master_controller.dm index c6e237935a7..e4e5b21b3d6 100644 --- a/code/game/master_controller.dm +++ b/code/game/master_controller.dm @@ -47,6 +47,8 @@ datum/controller/game_controller world.tick_lag = config.Ticklag + createRandomZlevel() + // Sleep for about 5 seconds to allow background initialization procs to finish sleep(50) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index a7dba9299a6..e44d45d7905 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -92,6 +92,12 @@ R.my_atom = src R.add_reagent("water", 50) +/obj/item/weapon/extinguisher/mini/New() + var/datum/reagents/R = new/datum/reagents(30) + reagents = R + R.my_atom = src + R.add_reagent("water", 30) + /obj/item/weapon/extinguisher/examine() set src in usr @@ -174,6 +180,19 @@ safety = 1 return +/obj/item/weapon/extinguisher/mini/attack_self(mob/user as mob) + if (safety) + src.icon_state = "miniFE1" + src.desc = "The safety is off." + user << "The safety is off." + safety = 0 + else + src.icon_state = "miniFE0" + src.desc = "The safety is on." + user << "The safety is on." + safety = 1 + return + /obj/item/weapon/pen/attack(mob/M as mob, mob/user as mob) if(!ismob(M)) return diff --git a/code/game/objects/items/weapons/cigs_lighters.dm b/code/game/objects/items/weapons/cigs_lighters.dm index 6c186a9b227..7e0c05a1768 100644 --- a/code/game/objects/items/weapons/cigs_lighters.dm +++ b/code/game/objects/items/weapons/cigs_lighters.dm @@ -4,6 +4,7 @@ MATCHES MATCHBOXES CIGARETTES CIGARS +SMOKING PIPES CIG PACKET ZIPPO */ @@ -329,7 +330,7 @@ ZIPPO //CIG PACK// //////////// /obj/item/weapon/cigpacket - name = "Cigarette packet" + name = "cigarette packet" desc = "The most popular brand of Space Cigarettes, sponsors of the Space Olympics." icon = 'cigarettes.dmi' icon_state = "cigpacket" @@ -342,26 +343,30 @@ ZIPPO update_icon() - src.icon_state = text("cigpacket[]", src.cigcount) - src.desc = text("There are [] cigs\s left!", src.cigcount) + icon_state = "[initial(icon_state)][cigcount]" + desc = "There's [cigcount] cig\s left!" return attack_hand(mob/user as mob) if(user.r_hand == src || user.l_hand == src) - if(src.cigcount == 0) + if(cigcount == 0) user << "\red You're out of cigs, shit! How you gonna get through the rest of the day..." return else - src.cigcount-- + cigcount-- var/obj/item/clothing/mask/cigarette/W = new /obj/item/clothing/mask/cigarette(user) user.put_in_hand(W) else return ..() - src.update_icon() + update_icon() return - +/obj/item/weapon/cigpacket/dromedaryco + name = "DromedaryCo packet" + desc = "A packet of six imported DromedaryCo cancer sticks. A label on the packaging reads, \"Wouldn't a slow death make a change?\"" + icon_state = "Dpacket" + item_state = "Dpacket" ///////// //ZIPPO// diff --git a/code/game/objects/mineral_doors.dm b/code/game/objects/mineral_doors.dm index 4b562b50744..17118f65f19 100644 --- a/code/game/objects/mineral_doors.dm +++ b/code/game/objects/mineral_doors.dm @@ -275,4 +275,33 @@ if(!devastated) for(var/i = 1, i <= oreAmount, i++) new/obj/item/stack/sheet/wood(get_turf(src)) + del(src) + +/obj/structure/mineral_door/resin + mineralType = "resin" + hardness = 5 + + Open() + isSwitchingStates = 1 + playsound(loc, 'attackblob.ogg', 100, 1) + flick("[mineralType]opening",src) + sleep(10) + density = 0 + opacity = 0 + state = 1 + update_icon() + isSwitchingStates = 0 + + Close() + isSwitchingStates = 1 + playsound(loc, 'attackblob.ogg', 100, 1) + flick("[mineralType]closing",src) + sleep(10) + density = 1 + opacity = 1 + state = 0 + update_icon() + isSwitchingStates = 0 + + Dismantle(devastated = 0) del(src) \ No newline at end of file diff --git a/code/game/objects/stacks/metal.dm b/code/game/objects/stacks/metal.dm index 02d72c107fe..9e6c74910eb 100644 --- a/code/game/objects/stacks/metal.dm +++ b/code/game/objects/stacks/metal.dm @@ -72,7 +72,7 @@ var/global/list/datum/stack_recipe/metal_recipes = list ( \ new/datum/stack_recipe("rack parts", /obj/item/weapon/rack_parts), \ new/datum/stack_recipe("closet", /obj/structure/closet, 2, one_per_turf = 1, on_floor = 1), \ null, \ - new/datum/stack_recipe("canister", /obj/machinery/portable_atmospherics/canister, 2, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("canister", /obj/machinery/portable_atmospherics/canister, 10, one_per_turf = 1, on_floor = 1), \ null, \ new/datum/stack_recipe("floor tile", /obj/item/stack/tile/plasteel, 1, 4, 10), \ new/datum/stack_recipe("metal rod", /obj/item/stack/rods, 1, 2, 60), \ diff --git a/code/game/objects/storage/crates.dm b/code/game/objects/storage/crates.dm index cb33970a13b..d4dd6126628 100644 --- a/code/game/objects/storage/crates.dm +++ b/code/game/objects/storage/crates.dm @@ -38,9 +38,18 @@ icon_opened = "crateopen" icon_closed = "crate" -/obj/structure/closet/crate/contraband - name = "Contraband crate" - desc = "A random assortment of items manufactured by providers NOT listed under Nanotrasen's whitelist." +/obj/structure/closet/crate/poster + name = "Poster crate" + desc = "A random assortment of posters manufactured by providers NOT listed under Nanotrasen's whitelist." + icon = 'storage.dmi' + icon_state = "crate" + density = 1 + icon_opened = "crateopen" + icon_closed = "crate" + +/obj/structure/closet/crate/cigarettes + name = "DromedaryCo cigarettes crate" + desc = "A crate of cigarettes manufactured by the notorious DromedaryCo company." icon = 'storage.dmi' icon_state = "crate" density = 1 diff --git a/code/game/objects/storage/toolbox.dm b/code/game/objects/storage/toolbox.dm index fb9df4919de..846aafcec41 100644 --- a/code/game/objects/storage/toolbox.dm +++ b/code/game/objects/storage/toolbox.dm @@ -1,7 +1,7 @@ /obj/item/weapon/storage/toolbox/emergency/New() ..() new /obj/item/weapon/crowbar/red(src) - new /obj/item/weapon/extinguisher(src) + new /obj/item/weapon/extinguisher/mini(src) if(prob(50)) new /obj/item/device/flashlight(src) new /obj/item/device/radio(src) diff --git a/code/game/verbs/who.dm b/code/game/verbs/who.dm index d2bc6e33c57..eb45379de53 100644 --- a/code/game/verbs/who.dm +++ b/code/game/verbs/who.dm @@ -33,7 +33,7 @@ if(usr.client.holder) usr << "[M.key] is a [M.client.holder.rank][M.client.stealth ? " (as [M.client.fakekey])" : ""]" else if(!M.client.stealth && (M.client.holder.level != -3)) - usr << "\t[pick(nobles)] [M.client]" + usr << "\t[pick(nobles)] [M.client] is a [M.client.holder.rank]" var/list/nobles = list("Baron","Bookkeeper","Captain of the Guard","Chief Medical Dwarf","Count","Dungeon Master","Duke","General","Mayor","Outpost Liaison","Sheriff","Champion") diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 4435bbf8f21..7574cfc2270 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -243,7 +243,7 @@ verbs += /client/proc/cmd_admin_world_narrate verbs += /client/proc/cmd_debug_del_all verbs += /client/proc/cmd_debug_tog_aliens - verbs += /client/proc/mapload +// verbs += /client/proc/mapload verbs += /client/proc/check_words verbs += /client/proc/drop_bomb verbs += /client/proc/kill_airgroup @@ -347,7 +347,7 @@ verbs -= /client/proc/Cell verbs -= /client/proc/cmd_debug_del_all verbs -= /client/proc/cmd_debug_tog_aliens - verbs -= /client/proc/mapload +// verbs -= /client/proc/mapload verbs -= /client/proc/check_words verbs -= /client/proc/drop_bomb //verbs -= /client/proc/cmd_admin_drop_everything --merged with view variables diff --git a/code/modules/admin/create_object.dm b/code/modules/admin/create_object.dm index 248eebb5ab9..0e74f2cab5a 100644 --- a/code/modules/admin/create_object.dm +++ b/code/modules/admin/create_object.dm @@ -15,7 +15,7 @@ var/quick_create_object_html = null var/pathtext = null - pathtext = input("Select the path of the object you wish to create.", "Path", "/obj") in list("/obj","/obj/structure","/obj/item","/obj/machinery") + pathtext = input("Select the path of the object you wish to create.", "Path", "/obj") in list("/obj","/obj/structure","/obj/item","/obj/item/weapon","/obj/machinery") var path = text2path(pathtext) diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index a3448267046..388729b9b1b 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -33,107 +33,108 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that /client/proc/callproc() set category = "Debug" set name = "Advanced ProcCall (TG Version)" + if(!holder) src << "Only administrators may use this command." return - var/target = null - var/lst[] // List reference - lst = new/list() // Make the list - var/returnval = null - var/class = null - switch(alert("Proc owned by something?",,"Yes","No")) - if("Yes") - class = input("Proc owned by...","Owner") in list("Obj","Mob","Area or Turf","Client","CANCEL ABORT STOP") + spawn(0) + var/target = null + var/targetselected = 0 + var/lst[] // List reference + lst = new/list() // Make the list + var/returnval = null + var/class = null + + switch(alert("Proc owned by something?",,"Yes","No")) + if("Yes") + targetselected = 1 + class = input("Proc owned by...","Owner",null) as null|anything in list("Obj","Mob","Area or Turf","Client") + switch(class) + if("Obj") + target = input("Enter target:","Target",usr) as obj in world + if("Mob") + target = input("Enter target:","Target",usr) as mob in world + if("Area or Turf") + target = input("Enter target:","Target",usr.loc) as area|turf in world + if("Client") + var/list/keys = list() + for(var/client/C) + keys += C + target = input("Please, select a player!", "Selection", null, null) as null|anything in keys + else + return + if("No") + target = null + targetselected = 0 + + var/procname = input("Proc path, eg: /proc/fake_blood","Path:", null) as text|null + if(!procname) return + + var/argnum = input("Number of arguments","Number:",0) as num|null + if(!argnum && (argnum!=0)) return + + lst.len = argnum // Expand to right length + //TODO: make a list to store whether each argument was initialised as null. + //Reason: So we can abort the proccall if say, one of our arguments was a mob which no longer exists + //this will protect us from a fair few errors ~Carn + + var/i + for(i=1, iError: callproc(): owner of proc no longer exists." + return + if(!hascall(target,procname)) + usr << "Error: callproc(): target has no such call [procname]." return - - if("text") - lst[i] = input("Enter new text:","Text",null) as text - - if("num") - lst[i] = input("Enter new number:","Num",0) as num - - if("type") - lst[i] = input("Enter type:","Type") in typesof(/obj,/mob,/area,/turf) - - if("reference") - switch(alert("Would you like to enter a specific object, or search for it from the world?","Choose!","Specifc UID (Hexadecimal number)", "Search")) - if("Specifc UID (Hexadecimal number)") - var/UID = input("Type in UID, without the leading 0x","Type in UID") as text|null - if(!UID) return - if(length(UID) != 7) - usr << "ERROR. UID must be 7 digits" - var/temp_variable = locate("\[0x[UID]\]") - if(!temp_variable) - usr << "ERROR. Could not locate referenced object." - return - switch(alert("You have chosen [temp_variable], in [get_area(temp_variable)]. Are you sure?","You sure?","Yes","NONOCANCEL!")) - if("Yes") - lst[i] = temp_variable - if("NONOCANCEL!") - return - if("Search") - lst[i] = input("Select reference:","Reference") as null|mob|obj|turf|area in world - - if("mob reference") - lst[i] = input("Select reference:","Reference",usr) as mob in getmobs() - - if("file") - lst[i] = input("Pick file:","File") as file - - if("icon") - lst[i] = input("Pick icon:","Icon") as icon - - if("client") - var/list/keys = list() - for(var/mob/M in world) - keys += M.client - sortList(keys) - lst[i] = input("Please, select a player!", "Selection", null, null) as null|anything in keys - - if("mob's area") - var/mob/temp = input("Select mob", "Selection", usr) as mob in getmobs() - lst[i] = temp.loc - - - spawn(0) - if(target) log_admin("[key_name(src)] called [target]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].") returnval = call(target,procname)(arglist(lst)) // Pass the lst as an argument list to the proc else + //this currently has no hascall protection. wasn't able to get it working. log_admin("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].") returnval = call(procname)(arglist(lst)) // Pass the lst as an argument list to the proc - usr << "\blue Proc returned: [returnval ? returnval : "null"]" + + usr << "[procname] returned: [returnval ? returnval : "null"]" + //feedback_add_details("admin_verb","APC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/callprocgen() set category = "Debug" @@ -286,6 +287,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that t+= "CO2: [env.carbon_dioxide]\n" usr.show_message(t, 1) + //feedback_add_details("admin_verb","ASL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/cmd_admin_robotize(var/mob/M in world) set category = "Fun" @@ -327,6 +329,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that for(var/datum/paiCandidate/candidate in paiController.pai_candidates) if(candidate.key == choice.key) paiController.pai_candidates.Remove(candidate) + //feedback_add_details("admin_verb","MPAI") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/cmd_admin_alienize(var/mob/M in world) set category = "Fun" @@ -466,6 +469,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that del(O) log_admin("[key_name(src)] has deleted all instances of [hsbitem].") message_admins("[key_name_admin(src)] has deleted all instances of [hsbitem].", 0) +// feedback_add_details("admin_verb","DELA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/cmd_debug_make_powernets() set category = "Debug" @@ -473,6 +477,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that makepowernets() log_admin("[key_name(src)] has remade the powernet. makepowernets() called.") message_admins("[key_name_admin(src)] has remade the powernets. makepowernets() called.", 0) +// feedback_add_details("admin_verb","MPWN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/cmd_debug_tog_aliens() set category = "Server" @@ -481,6 +486,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that aliens_allowed = !aliens_allowed log_admin("[key_name(src)] has turned aliens [aliens_allowed ? "on" : "off"].") message_admins("[key_name_admin(src)] has turned aliens [aliens_allowed ? "on" : "off"].", 0) +// feedback_add_details("admin_verb","TAL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/cmd_admin_grantfullaccess(var/mob/M in world) set category = "Admin" diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm index 41b9de1c19e..2cba4266bc4 100644 --- a/code/modules/assembly/signaler.dm +++ b/code/modules/assembly/signaler.dm @@ -143,6 +143,10 @@ proc/set_frequency(new_frequency) + if(!radio_controller) + sleep(20) + if(!radio_controller) + return radio_controller.remove_object(src, frequency) frequency = new_frequency radio_connection = radio_controller.add_object(src, frequency, RADIO_CHAT) diff --git a/code/modules/chemical/Chemistry-Machinery.dm b/code/modules/chemical/Chemistry-Machinery.dm index 2e31bce08f2..5215e4635fd 100644 --- a/code/modules/chemical/Chemistry-Machinery.dm +++ b/code/modules/chemical/Chemistry-Machinery.dm @@ -226,6 +226,7 @@ if(usr.stat || usr.restrained()) return if(!in_range(src, usr)) return + src.add_fingerprint(usr) usr.machine = src if(!beaker) return var/datum/reagents/R = beaker:reagents @@ -290,9 +291,9 @@ reagents.clear_reagents() icon_state = "mixer0" else if (href_list["createpill"]) - var/name = input(usr,"Name:","Name your pill!",reagents.get_master_reagent_name()) + var/name = reject_bad_text(input(usr,"Name:","Name your pill!",reagents.get_master_reagent_name())) var/obj/item/weapon/reagent_containers/pill/P = new/obj/item/weapon/reagent_containers/pill(src.loc) - if(!name || name == " ") name = reagents.get_master_reagent_name() + if(!name) name = reagents.get_master_reagent_name() P.name = "[name] pill" P.pixel_x = rand(-7, 7) //random position P.pixel_y = rand(-7, 7) @@ -300,9 +301,9 @@ reagents.trans_to(P,50) else if (href_list["createbottle"]) if(!condi) - var/name = input(usr,"Name:","Name your bottle!",reagents.get_master_reagent_name()) + var/name = reject_bad_text(input(usr,"Name:","Name your bottle!",reagents.get_master_reagent_name())) var/obj/item/weapon/reagent_containers/glass/bottle/P = new/obj/item/weapon/reagent_containers/glass/bottle(src.loc) - if(!name || name == " ") name = reagents.get_master_reagent_name() + if(!name) name = reagents.get_master_reagent_name() P.name = "[name] bottle" P.pixel_x = rand(-7, 7) //random position P.pixel_y = rand(-7, 7) @@ -334,7 +335,6 @@ else usr << browse(null, "window=chem_master") src.updateUsrDialog() - src.add_fingerprint(usr) return attack_ai(mob/user as mob) diff --git a/code/modules/chemical/Chemistry-Reagents.dm b/code/modules/chemical/Chemistry-Reagents.dm index c8f93e7c8cb..9030fa6a071 100644 --- a/code/modules/chemical/Chemistry-Reagents.dm +++ b/code/modules/chemical/Chemistry-Reagents.dm @@ -744,9 +744,7 @@ datum affecting.take_damage(25, 0) M:UpdateDamageIcon() M:emote("scream") - M << "\red Your face has become disfigured!" - M.real_name = "Unknown" - M.warn_flavor_changed() + M:disfigure_face() else M.take_organ_damage(min(15, volume * 2)) // uses min() and volume to make sure they aren't being sprayed in trace amounts (1 unit != insta rape) -- Doohl else @@ -798,10 +796,7 @@ datum M:UpdateDamageIcon() M:emote("scream") if(prob(15)) - M << "\red Your face has become disfigured!" - M.real_name = "Unknown" - M.warn_flavor_changed() - affecting.disfigured = 1 + M:disfigure_face() else if(istype(M, /mob/living/carbon/monkey) && M:wear_mask) del (M:wear_mask) @@ -819,10 +814,7 @@ datum M:UpdateDamageIcon() M:emote("scream") if(prob(15)) - M << "\red Your face has become disfigured!" - M.real_name = "Unknown" - M.warn_flavor_changed() - affecting.disfigured = 1 + M:disfigure_face() else M.take_organ_damage(min(15, volume * 4)) @@ -2930,9 +2922,9 @@ datum color = "#664300" // rgb: 102, 67, 0 tequilla_sunrise - name = "Tequilla Sunrise" + name = "Tequila Sunrise" id = "tequillasunrise" - description = "Tequilla and orange juice. Much like a Screwdriver, only Mexican~" + description = "Tequila and orange juice. Much like a Screwdriver, only Mexican~" reagent_state = LIQUID color = "#664300" // rgb: 102, 67, 0 @@ -3034,7 +3026,7 @@ datum manhattan_proj name = "Manhattan Project" id = "manhattan_proj" - description = "A scienitst drink of choice, for thinking how to blow up the station." + description = "A scienitst's drink of choice, for pondering ways to blow up the station." reagent_state = LIQUID color = "#664300" // rgb: 102, 67, 0 @@ -3110,6 +3102,180 @@ datum dizzy_adj = 15 slurr_adj = 15 + + sbiten + name = "Sbiten" + id = "sbiten" + description = "A spicy Vodka! Might be a little hot for the little guys!" + reagent_state = LIQUID + color = "#664300" // rgb: 102, 67, 0 + + on_mob_life(var/mob/living/M as mob) + if (M.bodytemperature < 360) + M.bodytemperature = min(360, M.bodytemperature+50) //310 is the normal bodytemp. 310.055 + return + + devilskiss + name = "Devils Kiss" + id = "devilskiss" + description = "Creepy time!" + reagent_state = LIQUID + color = "#A68310" // rgb: 166, 131, 16 + + red_mead + name = "Red Mead" + id = "red_mead" + description = "The true Viking drink! Even though it has a strange red color." + reagent_state = LIQUID + color = "#664300" // rgb: 102, 67, 0 + + mead + name = "Mead" + id = "mead" + description = "A Vikings drink, though a cheap one." + reagent_state = LIQUID + color = "#664300" // rgb: 102, 67, 0 + + iced_beer + name = "Iced Beer" + id = "iced_beer" + description = "A beer which is so cold the air around it freezes." + reagent_state = LIQUID + color = "#664300" // rgb: 102, 67, 0 + + on_mob_life(var/mob/living/M as mob) + if (M.bodytemperature < 270) + M.bodytemperature = min(270, M.bodytemperature-40) //310 is the normal bodytemp. 310.055 + return + + grog + name = "Grog" + id = "grog" + description = "Watered down rum, NanoTrasen approves!" + reagent_state = LIQUID + color = "#664300" // rgb: 102, 67, 0 + + aloe + name = "Aloe" + id = "aloe" + description = "So very, very, very good." + reagent_state = LIQUID + color = "#664300" // rgb: 102, 67, 0 + + andalusia + name = "Andalusia" + id = "andalusia" + description = "A nice, strange named drink." + reagent_state = LIQUID + color = "#664300" // rgb: 102, 67, 0 + + alliescocktail + name = "Allies Cocktail" + id = "alliescocktail" + description = "A drink made from your allies." + reagent_state = LIQUID + color = "#664300" // rgb: 102, 67, 0 + + acid_spit + name = "Acid Spit" + id = "acidspit" + description = "A drink by Nanotrasen. Made from live aliens." + reagent_state = LIQUID + color = "#365000" // rgb: 54, 80, 0 + + amasec + name = "Amasec" + id = "amasec" + description = "Official drink of the Imperium." + reagent_state = LIQUID + color = "#664300" // rgb: 102, 67, 0 + + on_mob_life(var/mob/living/M as mob) + M.stunned = 4 + return + + neurotoxin + name = "Neurotoxin" + id = "neurotoxin" + description = "A strong neurotoxin that puts the subject into a death-like state." + reagent_state = LIQUID + color = "#2E2E61" // rgb: 46, 46, 97 + + on_mob_life(var/mob/living/M as mob) + if(!M) M = holder.my_atom + M:adjustOxyLoss(0.5) + M:adjustOxyLoss(0.5) + M:weakened = max(M:weakened, 15) + M:silent = max(M:silent, 15) + return + + bananahonk + name = "Banana Mama" + id = "bananahonk" + description = "A drink from Clown Heaven." + nutriment_factor = 1 * REAGENTS_METABOLISM + color = "#664300" // rgb: 102, 67, 0 + + silencer + name = "Silencer" + id = "silencer" + description = "A drink from Mime Heaven." + nutriment_factor = 1 * REAGENTS_METABOLISM + color = "#664300" // rgb: 102, 67, 0 + + changelingsting + name = "Changeling Sting" + id = "changelingsting" + description = "A stingy drink." + reagent_state = LIQUID + color = "#2E6671" // rgb: 46, 102, 113 + + on_mob_life(var/mob/living/M as mob) + if(!data) data = 1 + data++ + M.dizziness +=5 + if(data >= 55 && data <115) + if (!M.slurring) M.slurring = 1 + M.slurring += 5 + else if(data >= 115 && prob(33)) + M.confused = max(M:confused+15,15) + ..() + return + + irishcarbomb + name = "Irish Car Bomb" + id = "irishcarbomb" + description = "Mmm, tastes like chocolate cake..." + reagent_state = LIQUID + color = "#2E6671" // rgb: 46, 102, 113 + + on_mob_life(var/mob/living/M as mob) + if(!data) data = 1 + data++ + M.dizziness +=5 + if(data >= 55 && data <115) + if (!M.slurring) M.slurring = 1 + M.slurring += 5 + else if(data >= 115 && prob(33)) + M.confused = max(M:confused+15,15) + ..() + return + + syndicatebomb + name = "Syndicate Bomb" + id = "syndicatebomb" + description = "A Syndicate bomb" + reagent_state = LIQUID + color = "#2E6671" // rgb: 46, 102, 113 + + erikasurprise + name = "Erika Surprise" + id = "erikasurprise" + description = "The surprise is, it's green!" + reagent_state = LIQUID + color = "#2E6671" // rgb: 46, 102, 113 + + //ALCHOHOL end tonic @@ -3175,192 +3341,8 @@ datum ..() return - ////////////////////////// REMOVED COCKTAIL REAGENTS BELOW:: RE-ENABLE THEM IF THEY EVER GET SPRITES THAT DON'T LOOK FUCKING STUPID --Agouri /////////////////////////// -/* sbiten - name = "Sbiten" - id = "sbiten" - description = "A spicy Vodka! Might be a little hot for the little guys!" - reagent_state = LIQUID - color = "#664300" // rgb: 102, 67, 0 - - on_mob_life(var/mob/living/M as mob) - if (M.bodytemperature < 360) - M.bodytemperature = min(360, M.bodytemperature+50) //310 is the normal bodytemp. 310.055 - if(!data) data = 1 - data++ - M.dizziness +=6 - if(data >= 45 && data <125) - if (!M.slurring) M.slurring = 1 - M.slurring += 6 - else if(data >= 125 && prob(33)) - M.confused = max(M:confused+5,5) - ..() - return - - devilskiss - name = "Devils Kiss" - id = "devilskiss" - description = "Creepy time!" - reagent_state = LIQUID - color = "#A68310" // rgb: 166, 131, 16 - - on_mob_life(var/mob/living/M as mob) - if(!data) data = 1 - data++ - M.dizziness +=4 - if(data >= 55 && data <165) - if (!M.slurring) M.slurring = 1 - M.slurring += 4 - else if(data >= 165 && prob(33)) - M.confused = max(M:confused+4,0) - ..() - return - - red_mead - name = "Red Mead" - id = "red_mead" - description = "The true Viking drink! Even though it has a strange red color." - reagent_state = LIQUID - color = "#664300" // rgb: 102, 67, 0 - - on_mob_life(var/mob/living/M as mob) - if(!data) data = 1 - data++ - M.dizziness +=5 - if(data >= 55 && data <115) - if (!M.slurring) M.slurring = 1 - M.slurring += 4 - else if(data >= 115 && prob(33)) - M.confused = max(M:confused+4,4) - ..() - return - - mead - name = "Mead" - id = "mead" - description = "A Vikings drink, though a cheap one." - reagent_state = LIQUID - color = "#664300" // rgb: 102, 67, 0 - - on_mob_life(var/mob/living/M as mob) - if(!data) data = 1 - data++ - M.make_dizzy(3) - M:jitteriness = max(M:jitteriness-3,0) - M:nutrition += 2 - if(data >= 25) - if (!M:slurring) M:slurring = 1 - M:slurring += 3 - if(data >= 40 && prob(33)) - if (!M:confused) M:confused = 1 - M:confused += 2 - - ..() - return - - iced_beer - name = "Iced Beer" - id = "iced_beer" - description = "A beer which is so cold the air around it freezes." - reagent_state = LIQUID - color = "#664300" // rgb: 102, 67, 0 - - on_mob_life(var/mob/living/M as mob) - if (M.bodytemperature < 270) - M.bodytemperature = min(270, M.bodytemperature-40) //310 is the normal bodytemp. 310.055 - if(!data) data = 1 - data++ - M.make_dizzy(3) - M:jitteriness = max(M:jitteriness-3,0) - M:nutrition += 2 - if(data >= 25) - if (!M:slurring) M:slurring = 1 - M:slurring += 3 - if(data >= 40 && prob(33)) - if (!M:confused) M:confused = 1 - M:confused += 2 - - ..() - return - - grog - name = "Grog" - id = "grog" - description = "Watered down rum, Nanotrasen approves!" - reagent_state = LIQUID - color = "#664300" // rgb: 102, 67, 0 - - on_mob_life(var/mob/living/M as mob) - if(!data) data = 1 - data++ - M.dizziness +=2 - if(data >= 90 && data <250) - if (!M.slurring) M.slurring = 1 - M.slurring += 2 - else if(data >= 250 && prob(33)) - M.confused = max(M:confused+2,0) - ..() - return - - aloe - name = "Aloe" - id = "aloe" - description = "So very, very, very good." - reagent_state = LIQUID - color = "#664300" // rgb: 102, 67, 0 - - on_mob_life(var/mob/living/M as mob) - if(!data) data = 1 - data++ - M.dizziness +=2 - if(data >= 90 && data <250) - if (!M.slurring) M.slurring = 1 - M.slurring += 2 - else if(data >= 250 && prob(33)) - M.confused = max(M:confused+2,0) - ..() - return - - andalusia - name = "Andalusia" - id = "andalusia" - description = "A nice, strange named drink." - reagent_state = LIQUID - color = "#664300" // rgb: 102, 67, 0 - - on_mob_life(var/mob/living/M as mob) - if(!data) data = 1 - data++ - M.dizziness +=8 - if(data >= 90 && data <250) - if (!M.slurring) M.slurring = 1 - M.slurring += 1 - else if(data >= 250 && prob(33)) - M.confused = max(M:confused+2,0) - ..() - return - - alliescocktail - name = "Allies Cocktail" - id = "alliescocktail" - description = "A drink made from your allies." - reagent_state = LIQUID - color = "#664300" // rgb: 102, 67, 0 - - on_mob_life(var/mob/living/M as mob) - if(!data) data = 1 - data++ - M.dizziness +=4 - if(data >= 90 && data <250) - if (!M.slurring) M.slurring = 1 - M.slurring += 7 - else if(data >= 250 && prob(60)) - M.confused = max(M:confused+8,0) - ..() - return - soy_latte name = "Soy Latte" id = "soy_latte" @@ -3401,75 +3383,8 @@ datum ..() return - acid_spit - name = "Acid Spit" - id = "acidspit" - description = "A drink by Nanotrasen. Made from live aliens." - reagent_state = LIQUID - color = "#365000" // rgb: 54, 80, 0 - - on_mob_life(var/mob/living/M as mob) - if(!data) data = 1 - data++ - M.dizziness +=10 - if(data >= 55 && data <115) - if (!M.slurring) M.slurring = 1 - M.slurring += 10 - else if(data >= 115 && prob(33)) - M.confused = max(M:confused+10,0) - ..() - return - - amasec - name = "Amasec" - id = "amasec" - description = "Always before COMBAT!!!" - reagent_state = LIQUID - color = "#664300" // rgb: 102, 67, 0 - - on_mob_life(var/mob/living/M as mob) - M.stunned = 4 - if(!data) data = 1 - data++ - M.dizziness +=4 - if(data >= 55 && data <165) - if (!M.slurring) M.slurring = 1 - M.slurring += 4 - else if(data >= 165 && prob(33)) - M.confused = max(M:confused+5,0) - ..() - return - - neurotoxin - name = "Neurotoxin" - id = "neurotoxin" - description = "A strong neurotoxin that puts the subject into a death-like state." - reagent_state = LIQUID - color = "#2E2E61" // rgb: 46, 46, 97 - - on_mob_life(var/mob/living/M as mob) - if(!M) M = holder.my_atom - M:adjustOxyLoss(0.5) - M:adjustOxyLoss(0.5) - M:weakened = max(M:weakened, 15) - M:silent = max(M:silent, 15) - if(!data) data = 1 - data++ - M.dizziness +=6 - if(data >= 15 && data <45) - if (!M.slurring) M.slurring = 1 - M.slurring += 3 - else if(data >= 45 && prob(50) && data <55) - M.confused = max(M:confused+3,0) - else if(data >=55) - M.druggy = max(M.druggy, 55) - ..() - - return - - hippies_delight - name = "Hippies Delight" + name = "Hippie's Delight" id = "hippiesdelight" description = "A drink enjoyed by people during the 1960's." reagent_state = LIQUID @@ -3499,139 +3414,4 @@ datum holder.remove_reagent(src.id, 0.2) data++ ..() - return - - bananahonk - name = "Banana Honk" - id = "bananahonk" - description = "A drink from Clown Heaven." - nutriment_factor = 1 * REAGENTS_METABOLISM - color = "#664300" // rgb: 102, 67, 0 - - on_mob_life(var/mob/living/M as mob) - M:nutrition += nutriment_factor - if(!data) data = 1 - data++ - if(istype(M, /mob/living/carbon/human) && M.job in list("Clown")) - if(!M) M = holder.my_atom - M:heal_organ_damage(1,1) - M.dizziness +=5 - if(data >= 55 && data <165) - if (!M.slurring) M.slurring = 1 - M.slurring += 5 - else if(data >= 165 && prob(33)) - M.confused = max(M:confused+5,0) - ..() - return - if(istype(M, /mob/living/carbon/monkey)) - if(!M) M = holder.my_atom - M:heal_organ_damage(1,1) - M.dizziness +=5 - if(data >= 55 && data <165) - if (!M.slurring) M.slurring = 1 - M.slurring += 5 - else if(data >= 165 && prob(33)) - M.confused = max(M:confused+5,0) - ..() - return - - silencer - name = "Silencer" - id = "silencer" - description = "A drink from Mime Heaven." - nutriment_factor = 1 * REAGENTS_METABOLISM - color = "#664300" // rgb: 102, 67, 0 - - on_mob_life(var/mob/living/M as mob) - M:nutrition += nutriment_factor - if(!data) data = 1 - data++ - if(istype(M, /mob/living/carbon/human) && M.job in list("Mime")) - if(!M) M = holder.my_atom - M:heal_organ_damage(1,1) - M.dizziness +=5 - if(data >= 55 && data <165) - if (!M.slurring) M.slurring = 1 - M.slurring += 5 - else if(data >= 165 && prob(33)) - M.confused = max(M:confused+5,0) - ..() - return - - - - changelingsting - name = "Changeling Sting" - id = "changelingsting" - description = "A stingy drink." - reagent_state = LIQUID - color = "#2E6671" // rgb: 46, 102, 113 - - on_mob_life(var/mob/living/M as mob) - if(!data) data = 1 - data++ - M.dizziness +=5 - if(data >= 55 && data <115) - if (!M.slurring) M.slurring = 1 - M.slurring += 5 - else if(data >= 115 && prob(33)) - M.confused = max(M:confused+15,15) - ..() - return - - irishcarbomb - name = "Irish Car Bomb" - id = "irishcarbomb" - description = "An irish car bomb" - reagent_state = LIQUID - color = "#2E6671" // rgb: 46, 102, 113 - - on_mob_life(var/mob/living/M as mob) - if(!data) data = 1 - data++ - M.dizziness +=5 - if(data >= 55 && data <115) - if (!M.slurring) M.slurring = 1 - M.slurring += 5 - else if(data >= 115 && prob(33)) - M.confused = max(M:confused+15,15) - ..() - return - - syndicatebomb - name = "Syndicate Bomb" - id = "syndicatebomb" - description = "A Syndicate bomb" - reagent_state = LIQUID - color = "#2E6671" // rgb: 46, 102, 113 - - on_mob_life(var/mob/living/M as mob) - if(!data) data = 1 - data++ - M.dizziness +=10 - if(data >= 55 && data <115) - if (!M.slurring) M.slurring = 1 - M.slurring += 10 - else if(data >= 115 && prob(33)) - M.confused = max(M:confused+15,15) - ..() - return - - erikasurprise - name = "Erika Surprise" - id = "erikasurprise" - description = "A surprise of Erika" - reagent_state = LIQUID - color = "#2E6671" // rgb: 46, 102, 113 - - on_mob_life(var/mob/living/M as mob) - if(!data) data = 1 - data++ - M.dizziness +=30 - if(data >= 55 && data <115) - if (!M.slurring) M.slurring = 1 - M.slurring += 30 - else if(data >= 115 && prob(60)) - M.confused = max(M:confused+15,15) - ..() - return*/ \ No newline at end of file + return \ No newline at end of file diff --git a/code/modules/chemical/Chemistry-Recipes.dm b/code/modules/chemical/Chemistry-Recipes.dm index c20935039ff..89c44b841cf 100644 --- a/code/modules/chemical/Chemistry-Recipes.dm +++ b/code/modules/chemical/Chemistry-Recipes.dm @@ -1261,7 +1261,7 @@ datum ////DRINKS THAT REQUIRE IMPROVED SPRITES BELOW:: -Agouri///// -/* sbiten + sbiten name = "Sbiten" id = "sbiten" result = "sbiten" @@ -1415,7 +1415,7 @@ datum id = "silencer" result = "silencer" required_reagents = list("nothing" = 1, "cream" = 1, "sugar" = 1) - result_amount = 3*/ + result_amount = 3 diff --git a/code/modules/chemical/Chemistry-Tools.dm b/code/modules/chemical/Chemistry-Tools.dm index 75aa27e081d..b8ef8668149 100644 --- a/code/modules/chemical/Chemistry-Tools.dm +++ b/code/modules/chemical/Chemistry-Tools.dm @@ -3498,8 +3498,7 @@ icon_state = "booger" name = "Booger" desc = "Ewww..." - - /*if("snowwhite") /// Dumbly-sprited drinks below. If your drink is on the list, shame on you --Agouri + if("snowwhite") icon_state = "snowwhite" name = "Snow White" desc = "A cold refreshment." @@ -3586,7 +3585,7 @@ if("erikasurprise") icon_state = "erikasurprise" name = "Erika Surprise" - desc = "A surprise of Erika"*/ + desc = "The surprise is, it's green!" else icon_state ="glass_brown" name = "Glass of ..what?" diff --git a/code/modules/clothing/gloves.dm b/code/modules/clothing/gloves.dm index 7cbd343cfca..e2192512d43 100644 --- a/code/modules/clothing/gloves.dm +++ b/code/modules/clothing/gloves.dm @@ -179,10 +179,7 @@ name = "botanist's leather gloves" icon_state = "leather" item_state = "ggloves" - siemens_coefficient = 0.50 permeability_coefficient = 0.9 - protective_temperature = 400 - heat_transfer_coefficient = 0.70 /obj/item/clothing/gloves/orange name = "orange gloves" diff --git a/code/modules/clothing/mask.dm b/code/modules/clothing/mask.dm index deed7760c99..1a8fc6d83b4 100644 --- a/code/modules/clothing/mask.dm +++ b/code/modules/clothing/mask.dm @@ -39,6 +39,14 @@ gas_transfer_coefficient = 0.01 permeability_coefficient = 0.01 +/obj/item/clothing/mask/balaclava + name = "balaclava" + desc = "LOADSAMONEY" + icon_state = "balaclava" + item_state = "balaclava" + flags = FPRINT|TABLEPASS|SUITSPACE|HEADSPACE|MASKCOVERSMOUTH|BLOCKHAIR + w_class = 2 + /obj/item/clothing/mask/muzzle name = "muzzle" desc = "To stop that awful noise." diff --git a/code/modules/maps/SwapMaps.dm b/code/modules/maps/SwapMaps.dm new file mode 100644 index 00000000000..be4f28edad4 --- /dev/null +++ b/code/modules/maps/SwapMaps.dm @@ -0,0 +1,672 @@ +/* + SwapMaps library by Lummox JR + developed for digitalBYOND + http://www.digitalbyond.org + + Version 2.1 + + The purpose of this library is to make it easy for authors to swap maps + in and out of their game using savefiles. Swapped-out maps can be + transferred between worlds for an MMORPG, sent to the client, etc. + This is facilitated by the use of a special datum and a global list. + + Uses of swapmaps: + + - Temporary battle arenas + - House interiors + - Individual custom player houses + - Virtually unlimited terrain + - Sharing maps between servers running different instances of the same + game + - Loading and saving pieces of maps for reusable room templates + */ + +/* + User Interface: + + VARS: + + swapmaps_iconcache + An associative list of icon files with names, like + 'player.dmi' = "player" + swapmaps_mode + This must be set at runtime, like in world/New(). + + SWAPMAPS_SAV 0 (default) + Uses .sav files for raw /savefile output. + SWAPMAPS_TEXT 1 + Uses .txt files via ExportText() and ImportText(). These maps + are easily editable and appear to take up less space in the + current version of BYOND. + + PROCS: + + SwapMaps_Find(id) + Find a map by its id + SwapMaps_Load(id) + Load a map by its id + SwapMaps_Save(id) + Save a map by its id (calls swapmap.Save()) + SwapMaps_Unload(id) + Save and unload a map by its id (calls swapmap.Unload()) + SwapMaps_Save_All() + Save all maps + SwapMaps_DeleteFile(id) + Delete a map file + SwapMaps_CreateFromTemplate(id) + Create a new map by loading another map to use as a template. + This map has id==src and will not be saved. To make it savable, + change id with swapmap.SetID(newid). + SwapMaps_LoadChunk(id,turf/locorner) + Load a swapmap as a "chunk", at a specific place. A new datum is + created but it's not added to the list of maps to save or unload. + The new datum can be safely deleted without affecting the turfs + it loaded. The purpose of this is to load a map file onto part of + another swapmap or an existing part of the world. + locorner is the corner turf with the lowest x,y,z values. + SwapMaps_SaveChunk(id,turf/corner1,turf/corner2) + Save a piece of the world as a "chunk". A new datum is created + for the chunk, but it can be deleted without destroying any turfs. + The chunk file can be reloaded as a swapmap all its own, or loaded + via SwapMaps_LoadChunk() to become part of another map. + SwapMaps_GetSize(id) + Return a list corresponding to the x,y,z sizes of a map file, + without loading the map. + Returns null if the map is not found. + SwapMaps_AddIconToCache(name,icon) + Cache an icon file by name for space-saving storage + + swapmap.New(id,x,y,z) + Create a new map; specify id, width (x), height (y), and + depth (z) + Default size is world.maxx,world.maxy,1 + swapmap.New(id,turf1,turf2) + Create a new map; specify id and 2 corners + This becomes a /swapmap for one of the compiled-in maps, for + easy saving. + swapmap.New() + Create a new map datum, but does not allocate space or assign an + ID (used for loading). + swapmap.Del() + Deletes a map but does not save + swapmap.Save() + Saves to map_[id].sav + Maps with id==src are not saved. + swapmap.Unload() + Saves the map and then deletes it + Maps with id==src are not saved. + swapmap.SetID(id) + Change the map's id and make changes to the lookup list + swapmap.AllTurfs(z) + Returns a block of turfs encompassing the entire map, or on just + one z-level + z is in world coordinates; it is optional + swapmap.Contains(turf/T) + Returns nonzero if T is inside the map's boundaries. + Also works for objs and mobs, but the proc is not area-safe. + swapmap.InUse() + Returns nonzero if a mob with a key is within the map's + boundaries. + swapmap.LoCorner(z=z1) + Returns locate(x1,y1,z), where z=z1 if none is specified. + swapmap.HiCorner(z=z2) + Returns locate(x2,y2,z), where z=z2 if none is specified. + swapmap.BuildFilledRectangle(turf/corner1,turf/corner2,item) + Builds a filled rectangle of item from one corner turf to the + other, on multiple z-levels if necessary. The corners may be + specified in any order. + item is a type path like /turf/wall or /obj/barrel{full=1}. + swapmap.BuildRectangle(turf/corner1,turf/corner2,item) + Builds an unfilled rectangle of item from one corner turf to + the other, on multiple z-levels if necessary. + swapmap.BuildInTurfs(list/turfs,item) + Builds item on all of the turfs listed. The list need not + contain only turfs, or even only atoms. + */ + +swapmap + var/id // a string identifying this map uniquely + var/x1 // minimum x,y,z coords + var/y1 + var/z1 + var/x2 // maximum x,y,z coords (also used as width,height,depth until positioned) + var/y2 + var/z2 + var/tmp/locked // don't move anyone to this map; it's saving or loading + var/tmp/mode // save as text-mode + var/ischunk // tells the load routine to load to the specified location + + New(_id,x,y,z) + if(isnull(_id)) return + id=_id + mode=swapmaps_mode + if(isturf(x) && isturf(y)) + /* + Special format: Defines a map as an existing set of turfs; + this is useful for saving a compiled map in swapmap format. + Because this is a compiled-in map, its turfs are not deleted + when the datum is deleted. + */ + x1=min(x:x,y:x);x2=max(x:x,y:x) + y1=min(x:y,y:y);y2=max(x:y,y:y) + z1=min(x:z,y:z);z2=max(x:z,y:z) + InitializeSwapMaps() + if(z2>swapmaps_compiled_maxz ||\ + y2>swapmaps_compiled_maxy ||\ + x2>swapmaps_compiled_maxx) + del(src) + return + x2=x?(x):world.maxx + y2=y?(y):world.maxy + z2=z?(z):1 + AllocateSwapMap() + + Del() + // a temporary datum for a chunk can be deleted outright + // for others, some cleanup is necessary + if(!ischunk) + swapmaps_loaded-=src + swapmaps_byname-=id + if(z2>swapmaps_compiled_maxz ||\ + y2>swapmaps_compiled_maxy ||\ + x2>swapmaps_compiled_maxx) + var/list/areas=new + for(var/atom/A in block(locate(x1,y1,z1),locate(x2,y2,z2))) + for(var/obj/O in A) del(O) + for(var/mob/M in A) + if(!M.key) del(M) + else M.loc=null + areas[A.loc]=null + del(A) + // delete areas that belong only to this map + for(var/area/a in areas) + if(a && !a.contents.len) del(a) + if(x2>=world.maxx || y2>=world.maxy || z2>=world.maxz) CutXYZ() + del(areas) + ..() + + /* + Savefile format: + map + id + x // size, not coords + y + z + areas // list of areas, not including default + [each z; 1 to depth] + [each y; 1 to height] + [each x; 1 to width] + type // of turf + AREA // if non-default; saved as a number (index into areas list) + vars // all other changed vars + */ + Write(savefile/S) + var + x;y;z;n + list/areas + area/defarea=locate(world.area) + if(!defarea) defarea=new world.area + areas=list() + for(var/turf/T in block(locate(x1,y1,z1),locate(x2,y2,z2))) + areas[T.loc]=null + for(n in areas) // quickly eliminate associations for smaller storage + areas-=n + areas+=n + areas-=defarea + InitializeSwapMaps() + locked=1 + S["id"] << id + S["z"] << z2-z1+1 + S["y"] << y2-y1+1 + S["x"] << x2-x1+1 + S["areas"] << areas + for(n in 1 to areas.len) areas[areas[n]]=n + var/oldcd=S.cd + for(z=z1,z<=z2,++z) + S.cd="[z-z1+1]" + for(y=y1,y<=y2,++y) + S.cd="[y-y1+1]" + for(x=x1,x<=x2,++x) + S.cd="[x-x1+1]" + var/turf/T=locate(x,y,z) + S["type"] << T.type + if(T.loc!=defarea) S["AREA"] << areas[T.loc] + T.Write(S) + S.cd=".." + S.cd=".." + sleep() + S.cd=oldcd + locked=0 + del(areas) + + Read(savefile/S,_id,turf/locorner) + var + x;y;z;n + list/areas + area/defarea=locate(world.area) + id=_id + if(locorner) + ischunk=1 + x1=locorner.x + y1=locorner.y + z1=locorner.z + if(!defarea) defarea=new world.area + if(!_id) + S["id"] >> id + else + var/dummy + S["id"] >> dummy + S["z"] >> z2 // these are depth, + S["y"] >> y2 // height, + S["x"] >> x2 // width + S["areas"] >> areas + locked=1 + AllocateSwapMap() // adjust x1,y1,z1 - x2,y2,z2 coords + var/oldcd=S.cd + for(z=z1,z<=z2,++z) + S.cd="[z-z1+1]" + for(y=y1,y<=y2,++y) + S.cd="[y-y1+1]" + for(x=x1,x<=x2,++x) + S.cd="[x-x1+1]" + var/tp + S["type"]>>tp + var/turf/T=locate(x,y,z) + T.loc.contents-=T + T=new tp(locate(x,y,z)) + if("AREA" in S.dir) + S["AREA"]>>n + var/area/A=areas[n] + A.contents+=T + else defarea.contents+=T + // clear the turf + for(var/obj/O in T) del(O) + for(var/mob/M in T) + if(!M.key) del(M) + else M.loc=null + // finish the read + T.Read(S) + S.cd=".." + S.cd=".." + sleep() + S.cd=oldcd + locked=0 + del(areas) + + /* + Find an empty block on the world map in which to load this map. + If no space is found, increase world.maxz as necessary. (If the + map is greater in x,y size than the current world, expand + world.maxx and world.maxy too.) + + Ignore certain operations if loading a map as a chunk. Use the + x1,y1,z1 position for it, and *don't* count it as a loaded map. + */ + proc/AllocateSwapMap() + InitializeSwapMaps() + world.maxx=max(x2,world.maxx) // stretch x/y if necessary + world.maxy=max(y2,world.maxy) + if(!ischunk) + if(world.maxz<=swapmaps_compiled_maxz) + z1=swapmaps_compiled_maxz+1 + x1=1;y1=1 + else + var/list/l=ConsiderRegion(1,1,world.maxx,world.maxy,swapmaps_compiled_maxz+1) + x1=l[1] + y1=l[2] + z1=l[3] + del(l) + x2+=x1-1 + y2+=y1-1 + z2+=z1-1 + world.maxz=max(z2,world.maxz) // stretch z if necessary + if(!ischunk) + swapmaps_loaded[src]=null + swapmaps_byname[id]=src + + proc/ConsiderRegion(X1,Y1,X2,Y2,Z1,Z2) + while(1) + var/nextz=0 + var/swapmap/M + for(M in swapmaps_loaded) + if(M.z2Z2) || M.z1>=Z1+z2 ||\ + M.x1>X2 || M.x2=X1+x2 ||\ + M.y1>Y2 || M.y2=Y1+y2) continue + // look for sub-regions with a defined ceiling + var/nz2=Z2?(Z2):Z1+z2-1+M.z2-M.z1 + if(M.x1>=X1+x2) + .=ConsiderRegion(X1,Y1,M.x1-1,Y2,Z1,nz2) + if(.) return + else if(M.x2<=X2-x2) + .=ConsiderRegion(M.x2+1,Y1,X2,Y2,Z1,nz2) + if(.) return + if(M.y1>=Y1+y2) + .=ConsiderRegion(X1,Y1,X2,M.y1-1,Z1,nz2) + if(.) return + else if(M.y2<=Y2-y2) + .=ConsiderRegion(X1,M.y2+1,X2,Y2,Z1,nz2) + if(.) return + nextz=nextz?min(nextz,M.z2+1):(M.z2+1) + if(!M) + /* If nextz is not 0, then at some point there was an overlap that + could not be resolved by using an area to the side */ + if(nextz) Z1=nextz + if(!nextz || (Z2 && Z2-Z1+1=z2)?list(X1,Y1,Z1):null + X1=1;X2=world.maxx + Y1=1;Y2=world.maxy + + proc/CutXYZ() + var/mx=swapmaps_compiled_maxx + var/my=swapmaps_compiled_maxy + var/mz=swapmaps_compiled_maxz + for(var/swapmap/M in swapmaps_loaded) // may not include src + mx=max(mx,M.x2) + my=max(my,M.y2) + mz=max(mz,M.z2) + world.maxx=mx + world.maxy=my + world.maxz=mz + + // save and delete + proc/Unload() + Save() + del(src) + + proc/Save() + if(id==src) return 0 + var/savefile/S=mode?(new):new("map_[id].sav") + S << src + while(locked) sleep(1) + if(mode) + fdel("map_[id].txt") + S.ExportText("/","map_[id].txt") + return 1 + + // this will not delete existing savefiles for this map + proc/SetID(newid) + swapmaps_byname-=id + id=newid + swapmaps_byname[id]=src + + proc/AllTurfs(z) + if(isnum(z) && (zz2)) return null + return block(LoCorner(z),HiCorner(z)) + + // this could be safely called for an obj or mob as well, but + // probably not an area + proc/Contains(turf/T) + return (T && T.x>=x1 && T.x<=x2\ + && T.y>=y1 && T.y<=y2\ + && T.z>=z1 && T.z<=z2) + + proc/InUse() + for(var/turf/T in AllTurfs()) + for(var/mob/M in T) if(M.key) return 1 + + proc/LoCorner(z=z1) + return locate(x1,y1,z) + proc/HiCorner(z=z2) + return locate(x2,y2,z) + + /* + Build procs: Take 2 turfs as corners, plus an item type. + An item may be like: + + /turf/wall + /obj/fence{icon_state="iron"} + */ + proc/BuildFilledRectangle(turf/T1,turf/T2,item) + if(!Contains(T1) || !Contains(T2)) return + var/turf/T=T1 + // pick new corners in a block()-friendly form + T1=locate(min(T1.x,T2.x),min(T1.y,T2.y),min(T1.z,T2.z)) + T2=locate(max(T.x,T2.x),max(T.y,T2.y),max(T.z,T2.z)) + for(T in block(T1,T2)) new item(T) + + proc/BuildRectangle(turf/T1,turf/T2,item) + if(!Contains(T1) || !Contains(T2)) return + var/turf/T=T1 + // pick new corners in a block()-friendly form + T1=locate(min(T1.x,T2.x),min(T1.y,T2.y),min(T1.z,T2.z)) + T2=locate(max(T.x,T2.x),max(T.y,T2.y),max(T.z,T2.z)) + if(T2.x-T1.x<2 || T2.y-T1.y<2) BuildFilledRectangle(T1,T2,item) + else + //for(T in block(T1,T2)-block(locate(T1.x+1,T1.y+1,T1.z),locate(T2.x-1,T2.y-1,T2.z))) + for(T in block(T1,locate(T2.x,T1.y,T2.z))) new item(T) + for(T in block(locate(T1.x,T2.y,T1.z),T2)) new item(T) + for(T in block(locate(T1.x,T1.y+1,T1.z),locate(T1.x,T2.y-1,T2.z))) new item(T) + for(T in block(locate(T2.x,T1.y+1,T1.z),locate(T2.x,T2.y-1,T2.z))) new item(T) + + /* + Supplementary build proc: Takes a list of turfs, plus an item + type. Actually the list doesn't have to be just turfs. + */ + proc/BuildInTurfs(list/turfs,item) + for(var/T in turfs) new item(T) + +atom + Write(savefile/S) + for(var/V in vars-"x"-"y"-"z"-"contents"-"icon"-"overlays"-"underlays") + if(issaved(vars[V])) + if(vars[V]!=initial(vars[V])) S[V]<>ic + if(istext(ic)) icon=swapmaps_iconcache[ic] + if(l && contents!=l) + contents+=l + del(l) + + +// set this up (at runtime) as follows: +// list(\ +// 'player.dmi'="player",\ +// 'monster.dmi'="monster",\ +// ... +// 'item.dmi'="item") +var/list/swapmaps_iconcache + +// preferred mode; sav or text +var/const/SWAPMAPS_SAV=0 +var/const/SWAPMAPS_TEXT=1 +var/swapmaps_mode=SWAPMAPS_SAV + +var/swapmaps_compiled_maxx +var/swapmaps_compiled_maxy +var/swapmaps_compiled_maxz +var/swapmaps_initialized +var/swapmaps_loaded +var/swapmaps_byname + +proc/InitializeSwapMaps() + if(swapmaps_initialized) return + swapmaps_initialized=1 + swapmaps_compiled_maxx=world.maxx + swapmaps_compiled_maxy=world.maxy + swapmaps_compiled_maxz=world.maxz + swapmaps_loaded=list() + swapmaps_byname=list() + if(swapmaps_iconcache) + for(var/V in swapmaps_iconcache) + // reverse-associate everything + // so you can look up an icon file by name or vice-versa + swapmaps_iconcache[swapmaps_iconcache[V]]=V + +proc/SwapMaps_AddIconToCache(name,icon) + if(!swapmaps_iconcache) swapmaps_iconcache=list() + swapmaps_iconcache[name]=icon + swapmaps_iconcache[icon]=name + +proc/SwapMaps_Find(id) + InitializeSwapMaps() + return swapmaps_byname[id] + +proc/SwapMaps_Load(id) + InitializeSwapMaps() + var/swapmap/M=swapmaps_byname[id] + if(!M) + var/savefile/S + var/text=0 + if(swapmaps_mode==SWAPMAPS_TEXT && fexists("map_[id].txt")) + text=1 + else if(fexists("map_[id].sav")) + S=new("map_[id].sav") + else if(swapmaps_mode!=SWAPMAPS_TEXT && fexists("map_[id].txt")) + text=1 + else return // no file found + if(text) + S=new + S.ImportText("/",file("map_[id].txt")) + S >> M + while(M.locked) sleep(1) + M.mode=text + return M + +proc/SwapMaps_Save(id) + InitializeSwapMaps() + var/swapmap/M=swapmaps_byname[id] + if(M) M.Save() + return M + +proc/SwapMaps_Save_All() + InitializeSwapMaps() + for(var/swapmap/M in swapmaps_loaded) + if(M) M.Save() + +proc/SwapMaps_Unload(id) + InitializeSwapMaps() + var/swapmap/M=swapmaps_byname[id] + if(!M) return // return silently from an error + M.Unload() + return 1 + +proc/SwapMaps_DeleteFile(id) + fdel("map_[id].sav") + fdel("map_[id].txt") + +proc/SwapMaps_CreateFromTemplate(template_id) + var/swapmap/M=new + var/savefile/S + var/text=0 + if(swapmaps_mode==SWAPMAPS_TEXT && fexists("map_[template_id].txt")) + text=1 + else if(fexists("map_[template_id].sav")) + S=new("map_[template_id].sav") + else if(swapmaps_mode!=SWAPMAPS_TEXT && fexists("map_[template_id].txt")) + text=1 + else + world.log << "SwapMaps error in SwapMaps_CreateFromTemplate(): map_[template_id] file not found." + return + if(text) + S=new + S.ImportText("/",file("map_[template_id].txt")) + /* + This hacky workaround is needed because S >> M will create a brand new + M to fill with data. There's no way to control the Read() process + properly otherwise. The //.0 path should always match the map, however. + */ + S.cd="//.0" + M.Read(S,M) + M.mode=text + while(M.locked) sleep(1) + return M + +proc/SwapMaps_LoadChunk(chunk_id,turf/locorner) + var/swapmap/M=new + var/savefile/S + var/text=0 + if(swapmaps_mode==SWAPMAPS_TEXT && fexists("map_[chunk_id].txt")) + text=1 + else if(fexists("map_[chunk_id].sav")) + S=new("map_[chunk_id].sav") + else if(swapmaps_mode!=SWAPMAPS_TEXT && fexists("map_[chunk_id].txt")) + text=1 + else + world.log << "SwapMaps error in SwapMaps_LoadChunk(): map_[chunk_id] file not found." + return + if(text) + S=new + S.ImportText("/",file("map_[chunk_id].txt")) + /* + This hacky workaround is needed because S >> M will create a brand new + M to fill with data. There's no way to control the Read() process + properly otherwise. The //.0 path should always match the map, however. + */ + S.cd="//.0" + M.Read(S,M,locorner) + while(M.locked) sleep(1) + del(M) + return 1 + +proc/SwapMaps_SaveChunk(chunk_id,turf/corner1,turf/corner2) + if(!corner1 || !corner2) + world.log << "SwapMaps error in SwapMaps_SaveChunk():" + if(!corner1) world.log << " corner1 turf is null" + if(!corner2) world.log << " corner2 turf is null" + return + var/swapmap/M=new + M.id=chunk_id + M.ischunk=1 // this is a chunk + M.x1=min(corner1.x,corner2.x) + M.y1=min(corner1.y,corner2.y) + M.z1=min(corner1.z,corner2.z) + M.x2=max(corner1.x,corner2.x) + M.y2=max(corner1.y,corner2.y) + M.z2=max(corner1.z,corner2.z) + M.mode=swapmaps_mode + M.Save() + while(M.locked) sleep(1) + del(M) + return 1 + +proc/SwapMaps_GetSize(id) + var/savefile/S + var/text=0 + if(swapmaps_mode==SWAPMAPS_TEXT && fexists("map_[id].txt")) + text=1 + else if(fexists("map_[id].sav")) + S=new("map_[id].sav") + else if(swapmaps_mode!=SWAPMAPS_TEXT && fexists("map_[id].txt")) + text=1 + else + world.log << "SwapMaps error in SwapMaps_GetSize(): map_[id] file not found." + return + if(text) + S=new + S.ImportText("/",file("map_[id].txt")) + /* + The //.0 path should always be the map. There's no other way to + read this data. + */ + S.cd="//.0" + var/x + var/y + var/z + S["x"] >> x + S["y"] >> y + S["z"] >> z + return list(x,y,z) diff --git a/code/modules/maps/dmm_suite.dm b/code/modules/maps/dmm_suite.dm new file mode 100644 index 00000000000..e2311ed7eee --- /dev/null +++ b/code/modules/maps/dmm_suite.dm @@ -0,0 +1,73 @@ +var/global/dmm_suite/maploader = new + +dmm_suite{ + /* + + dmm_suite version 1.0 + Released January 30th, 2011. + + defines the object /dmm_suite + - Provides the proc load_map() + - Loads the specified map file onto the specified z-level. + - provides the proc write_map() + - Returns a text string of the map in dmm format + ready for output to a file. + - provides the proc save_map() + - Returns a .dmm file if map is saved + - Returns FALSE if map fails to save + + The dmm_suite provides saving and loading of map files in BYOND's native DMM map + format. It approximates the map saving and loading processes of the Dream Maker + and Dream Seeker programs so as to allow editing, saving, and loading of maps at + runtime. + + ------------------------ + + To save a map at runtime, create an instance of /dmm_suite, and then call + write_map(), which accepts three arguments: + - A turf representing one corner of a three dimensional grid (Required). + - Another turf representing the other corner of the same grid (Required). + - Any, or a combination, of several bit flags (Optional, see documentation). + + The order in which the turfs are supplied does not matter, the /dmm_writer will + determine the grid containing both, in much the same way as DM's block() function. + write_map() will then return a string representing the saved map in dmm format; + this string can then be saved to a file, or used for any other purose. + + ------------------------ + + To load a map at runtime, create an instance of /dmm_suite, and then call load_map(), + which accepts two arguments: + - A .dmm file to load (Required). + - A number representing the z-level on which to start loading the map (Optional). + + The /dmm_suite will load the map file starting on the specified z-level. If no + z-level was specified, world.maxz will be increased so as to fit the map. Note + that if you wish to load a map onto a z-level that already has objects on it, + you will have to handle the removal of those objects. Otherwise the new map will + simply load the new objects on top of the old ones. + + Also note that all type paths specified in the .dmm file must exist in the world's + code, and that the /dmm_reader trusts that files to be loaded are in fact valid + .dmm files. Errors in the .dmm format will cause runtime errors. + + */ + + verb/load_map(var/dmm_file as file, var/z_offset as num){ + // dmm_file: A .dmm file to load (Required). + // z_offset: A number representing the z-level on which to start loading the map (Optional). + } + verb/write_map(var/turf/t1 as turf, var/turf/t2 as turf, var/flags as num){ + // t1: A turf representing one corner of a three dimensional grid (Required). + // t2: Another turf representing the other corner of the same grid (Required). + // flags: Any, or a combination, of several bit flags (Optional, see documentation). + } + + // save_map is included as a legacy proc. Use write_map instead. + verb/save_map(var/turf/t1 as turf, var/turf/t2 as turf, var/map_name as text, var/flags as num){ + // t1: A turf representing one corner of a three dimensional grid (Required). + // t2: Another turf representing the other corner of the same grid (Required). + // map_name: A valid name for the map to be saved, such as "castle" (Required). + // flags: Any, or a combination, of several bit flags (Optional, see documentation). + } + } \ No newline at end of file diff --git a/code/modules/maps/fromdmp.dm b/code/modules/maps/fromdmp.dm new file mode 100644 index 00000000000..73958b43a8c --- /dev/null +++ b/code/modules/maps/fromdmp.dm @@ -0,0 +1,237 @@ +/* + DMP to swapmap converter + version 1.0 + + by Lummox JR + */ + +mob/verb/Convert(filename as file) + dmp2swapmap(filename) + +proc/d2sm_prepmap(filename) + var/txt = file2text(filename) + if(!txt) return + var/i,j + i=findText(txt,ascii2text(13)) // eliminate carriage returns + while(i) + txt=copytext(txt,1,i)+copytext(txt,i+1) + i=findText(txt,ascii2text(13),i) + i=findText(txt,"\\\n") + while(i) + for(j=i+2,j<=length(txt),++j) if(text2ascii(txt,j)>32) break + txt=copytext(txt,1,i)+copytext(txt,j) + i=findText(txt,"\\\n",i) + return txt + +proc/dmp2swapmap(filename) + //var/txt = file2text(filename) + //if(!txt) return + var/txt = d2sm_prepmap(filename) + var/mapname="[filename]" + var/i,j,k + i=findtext(mapname,".dmp") + while(i && i+432) break + txt=copytext(txt,1,i)+copytext(txt,j) + i=findText(txt,"\\\n",i) */ + var/list/codes=new + var/codelen=1 + var/list/areas + var/mode=34 + var/z=0 + var/X=0,Y=0,Z=0 + while(txt) + if(text2ascii(txt)==34) + if(mode!=34) + world << "Corrupt map file [filename]: Unexpected code found after z-level [z]" + return + // standard line: + // "a" = (/obj, /obj, /turf, /area) + i=findtext(txt,"\"",2) + var/code=copytext(txt,2,i) + codelen=length(code) + i=findtext(txt,"(",i) + if(!i) + world << "Corrupt map file [filename]: No type list follows \"[code]\"" + return + k=findtext(txt,"\n",++i) + j=(k || length(txt+1)) + while(--j>=i && text2ascii(txt,j)!=41) + if(j2) codetrans+=d2sm_Contents(L,L.len-2,"\t\t\t\t") + codes[code]=copytext(codetrans,1,length(codetrans)) + else if(text2ascii(txt)==40) + mode=40 + // standard line (top-down, left-right symbol order): + // (1,1,1) = {" + // abcde + // bcdef + // "} + i=d2sm_MatchBrace(txt,1,40) + if(!i) + world << "Corrupt map file [filename]: No matching ) for coordinates: [copytext(txt,1,findtext(txt,"\n"))]" + return + var/list/coords=d2sm_ParseCommaList(copytext(txt,2,i)) + if(istext(coords) || coords.len!=3) + world << "Corrupt map file [filename]: [istext(coords)?(coords):"[copytext(txt,1,i+1)] is not a valid (x,y,z) coordinate"]" + return + j=findtext(txt,"{",i+1) + if(!j) + world << "Corrupt map file [filename]: No braces {} following [copytext(txt,1,i+1)]" + return + k=d2sm_MatchBrace(txt,j,123) + if(!k) + world << "Corrupt map file [filename]: No closing brace } following [copytext(txt,1,i+1)]" + return + var/mtxt=copytext(txt,j+1,k) + if(findText(mtxt,"\"\n")!=1 || !findText(mtxt,"\n\"",length(mtxt)-1)) + world << findText(mtxt,"\"\n") + world << findText(mtxt,"\n\"",length(mtxt)-1) + world << "Corrupt map file [filename]: No quotes in braces following [copytext(txt,1,i+1)]" + return + mtxt=copytext(mtxt,2,length(mtxt)) + var/_x=0,_y=0 + for(i=1,,++_y) + j=findText(mtxt,"\n",i+1) + if(!j) break + _x=max(_x,(j-i-1)/codelen) + i=j + X=max(X,_x) + Y=max(Y,_y) + z=text2num(coords[3]) + Z=max(Z,z) + txt=copytext(txt,k+1) + else + i=findtext(txt,"\n") + txt=i?copytext(txt,i+1):null + world << "Map size: [X],[Y],[Z]" + //for(var/code in codes) + // world << "Code \"[code]\":\n[codes[code]]" + fdel("map_[mapname].txt") + var/F = file("map_[mapname].txt") + F << ". = object(\".0\")\n.0\n\ttype = /swapmap\n\tid = \"[mapname]\"\n\tz = [Z]\n\ty = [Y]\n\tx = [X]" + if(areas) + txt="" + for(i=0,i0,--y) // map is top-down + ++i + F << "\t\t[y]" + for(var/x in 1 to _x) + F << "\t\t\t[x]" + j=i+codelen + F << codes[copytext(mtxt,i,j)] + i=j + txt=copytext(txt,k+1) + /* for(z in 1 to Z) + F << "\t[z]" + for(var/y in 1 to Y) + F << "\t\t[y]" + for(var/x in 1 to X) + F << "\t\t\t[x]" + F << codes[pick(codes)] */ + +proc/d2sm_ParseCommaList(txt) + var/list/L=new + var/i,ch + for(i=1,i<=length(txt),++i) + if(text2ascii(txt,i)>32) break + for(,i<=length(txt),++i) + ch=text2ascii(txt,i) + if(ch==44) + L+=copytext(txt,1,i) + for(++i,i<=length(txt),++i) if(text2ascii(txt,i)>32) break + txt=copytext(txt,i) + i=0;continue + if(ch==40 || ch==91 || ch==123) + i=d2sm_MatchBrace(txt,i,ch) + if(!i) return "No matching brace found for [ascii2text(ch)]" + if(i>1) L+=copytext(txt,1,i) + return L + +proc/d2sm_MatchBrace(txt, i, which) + if(which==40) ++which + else which+=2 + var/j,ch + for(j=i+1,j<=length(txt),++j) + ch=text2ascii(txt,j) + if(ch==which) return j + if(ch==40 || ch==91 || ch==123) + j=d2sm_MatchBrace(txt,j,ch) + if(!j) return 0 + +proc/d2sm_ConvertType(tt,tabs="") + var/i=findText(tt,"{") + if(!i) return "[tabs]type = [tt]\n" + .="[tabs]type = [copytext(tt,1,i)]\n" + var/list/L=d2sm_ParseCommaList(copytext(tt,i+1,d2sm_MatchBrace(tt,i,123))) + if(istext(L)) return + for(var/pair in L) + .="[.][tabs][pair]\n" + +proc/d2sm_Contents(list/conts,n,tabs="") + .="[tabs]contents = list(" + var/i + for(i=0,ilength(zgrid)){break} + sleep(-1) + } + if(findtext(tfile,quote+"}",zpos,0)+2==tfile_len){break} + sleep(-1) + } + } + proc{ + parse_grid(var/model as text,var/xcrd as num,var/ycrd as num,var/zcrd as num){ + /*Method parse_grid() + - Accepts a text string containing a comma separated list of type paths of the + same construction as those contained in a .dmm file, and instantiates them. + */ + var/list/text_strings[0] + for(var/index=1;findtext(model,quote);index++){ + /*Loop: Stores quoted portions of text in text_strings, and replaces them with an + index to that list. + - Each iteration represents one quoted section of text. + */ + text_strings.len=index + text_strings[index] = copytext(model,findtext(model,quote)+1,findtext(model,quote,findtext(model,quote)+1,0)) + model = copytext(model,1,findtext(model,quote))+"~[index]"+copytext(model,findtext(model,quote,findtext(model,quote)+1,0)+1,0) + sleep(-1) + } + var/list/old_turf_underlays[0] + var/old_turf_density + var/old_turf_opacity + /*The old_turf variables store information about turfs instantiated in this location/iteration. + This is done to approximate the layered turf effect of DM's map editor. + An image of each turf is stored in old_turf_underlays[], and is later added to the new turf's underlays. + */ + for(var/dpos=1;dpos!=0;dpos=findtext(model,",",dpos,0)+1){ + /*Loop: Identifies each object's data, instantiates it, and reconstitues it's fields. + - Each iteration represents one object's data, including type path and field values. + */ + var/full_def = copytext(model,dpos,findtext(model,",",dpos,0)) + var/atom_def = text2path(copytext(full_def,1,findtext(full_def,"{"))) + var/list/attributes[0] + if(findtext(full_def,"{")){ + full_def = copytext(full_def,1,length(full_def)) + for(var/apos=findtext(full_def,"{")+1;apos!=0;apos=findtext(full_def,";",apos,0)+1){ + //Loop: Identifies each attribute/value pair, and stores it in attributes[]. + attributes.Add(copytext(full_def,apos,findtext(full_def,";",apos,0))) + if(!findtext(copytext(full_def,apos,0),";")){break} + sleep(-1) + } + } + //Construct attributes associative list + var/list/fields = new(0) + for(var/index=1;index<=attributes.len;index++){ + var/trim_left = trim_text(copytext(attributes[index],1,findtext(attributes[index],"="))) + var/trim_right = trim_text(copytext(attributes[index],findtext(attributes[index],"=")+1,0)) + //Check for string + if(findtext(trim_right,"~")){ + var/reference_index = copytext(trim_right,findtext(trim_right,"~")+1,0) + trim_right=text_strings[text2num(reference_index)] + } + //Check for number + else if(isnum(text2num(trim_right))){ + trim_right = text2num(trim_right) + } + //Check for file + else if(copytext(trim_right,1,2) == "'"){ + trim_right = file(copytext(trim_right,2,length(trim_right))) + } + fields[trim_left] = trim_right + } + //End construction + + + //Begin Instanciation + var/atom/instance + var/dmm_suite/preloader/_preloader = new(fields) + if(ispath(atom_def,/area)){ + instance = locate(atom_def) + instance.contents.Add(locate(xcrd,ycrd,zcrd)) + } + else if(ispath(atom_def,/turf)){ + var/turf/old_turf = locate(xcrd,ycrd,zcrd) + if(old_turf.density){old_turf_density = 1} + if(old_turf.opacity){old_turf_opacity = 1} + if(old_turf.icon){ + var/image/old_turf_image = image(old_turf.icon,null,old_turf.icon_state,old_turf.layer,old_turf.dir) + old_turf_underlays.Add(old_turf_image) + } + instance = new atom_def(old_turf, _preloader) + for(var/inverse_index=old_turf_underlays.len;inverse_index;inverse_index--){ + var/image/image_underlay = old_turf_underlays[inverse_index] + image_underlay.loc = instance + instance.underlays.Add(image_underlay) + } + if(!instance.density){instance.density = old_turf_density} + if(!instance.opacity){instance.opacity = old_turf_opacity} + } + + if(_preloader && instance){ + _preloader.load(instance) + } + //End Instanciation + if(!findtext(copytext(model,dpos,0),",")){break} + sleep(-1) + } +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + for(var/dpos=1;dpos!=0;dpos=findtext(model,",",dpos,0)+1) + { + /*Loop: Identifies each object's data, instantiates it, and reconstitues it's fields. + - Each iteration represents one object's data, including type path and field values. + */ + var/full_def = copytext(model,dpos,findtext(model,",",dpos,0)) + var/atom_def = text2path(copytext(full_def,1,findtext(full_def,"{"))) + var/list/attributes[0] + if(findtext(full_def,"{")){ + full_def = copytext(full_def,1,length(full_def)) + for(var/apos=findtext(full_def,"{")+1;apos!=0;apos=findtext(full_def,";",apos,0)+1){ + //Loop: Identifies each attribute/value pair, and stores it in attributes[]. + attributes.Add(copytext(full_def,apos,findtext(full_def,";",apos,0))) + if(!findtext(copytext(full_def,apos,0),";")){break} + sleep(-1) + } + } + //Construct attributes associative list + var/list/fields = new(0) + for(var/index=1;index<=attributes.len;index++){ + var/trim_left = trim_text(copytext(attributes[index],1,findtext(attributes[index],"="))) + var/trim_right = trim_text(copytext(attributes[index],findtext(attributes[index],"=")+1,0)) + //Check for string + if(findtext(trim_right,"~")){ + var/reference_index = copytext(trim_right,findtext(trim_right,"~")+1,0) + trim_right=text_strings[text2num(reference_index)] + } + //Check for number + else if(isnum(text2num(trim_right))){ + trim_right = text2num(trim_right) + } + //Check for file + else if(copytext(trim_right,1,2) == "'"){ + trim_right = file(copytext(trim_right,2,length(trim_right))) + } + fields[trim_left] = trim_right + } + //End construction + + + //Begin Instanciation + var/atom/instance + var/dmm_suite/preloader/_preloader = new(fields) + if(!ispath(atom_def,/area) && !ispath(atom_def,/turf)) + { + instance = new atom_def(locate(xcrd,ycrd,zcrd), _preloader) + } + + + if(_preloader && instance) + { + _preloader.load(instance) + } + //End Instanciation + if(!findtext(copytext(model,dpos,0),",")){break} + sleep(-1) + } + + + + + } + trim_text(var/what as text){ + while(length(what) && findtext(what," ",1,2)){ + what=copytext(what,2,0) + } + while(length(what) && findtext(what," ",length(what),0)){ + what=copytext(what,1,length(what)) + } + return what + } + } + } +atom/New(atom/loc, dmm_suite/preloader/_dmm_preloader){ + if(istype(_dmm_preloader, /dmm_suite/preloader)){ + _dmm_preloader.load(src) + } + . = ..() + } +dmm_suite{ + preloader{ + parent_type = /datum + var{ + list/attributes + } + New(list/the_attributes){ + .=..() + if(!the_attributes.len){ Del()} + attributes = the_attributes + } + proc{ + load(atom/what){ + for(var/attribute in attributes){ + what.vars[attribute] = attributes[attribute] + } + Del() + } + } + } + } + diff --git a/code/modules/maps/writer.dm b/code/modules/maps/writer.dm new file mode 100644 index 00000000000..81c6a396033 --- /dev/null +++ b/code/modules/maps/writer.dm @@ -0,0 +1,174 @@ +#define DMM_IGNORE_AREAS 1 +#define DMM_IGNORE_TURFS 2 +#define DMM_IGNORE_OBJS 4 +#define DMM_IGNORE_NPCS 8 +#define DMM_IGNORE_PLAYERS 16 +#define DMM_IGNORE_MOBS 24 +dmm_suite{ + var{ + quote = "\"" + list/letter_digits = list( + "a","b","c","d","e", + "f","g","h","i","j", + "k","l","m","n","o", + "p","q","r","s","t", + "u","v","w","x","y", + "z", + "A","B","C","D","E", + "F","G","H","I","J", + "K","L","M","N","O", + "P","Q","R","S","T", + "U","V","W","X","Y", + "Z" + ) + } + save_map(var/turf/t1 as turf, var/turf/t2 as turf, var/map_name as text, var/flags as num){ + //Check for illegal characters in file name... in a cheap way. + if(!((ckeyEx(map_name)==map_name) && ckeyEx(map_name))){ + CRASH("Invalid text supplied to proc save_map, invalid characters or empty string.") + } + //Check for valid turfs. + if(!isturf(t1) || !isturf(t2)){ + CRASH("Invalid arguments supplied to proc save_map, arguments were not turfs.") + } + var/file_text = write_map(t1,t2,flags) + if(fexists("[map_name].dmm")){ + fdel("[map_name].dmm") + } + var/saved_map = file("[map_name].dmm") + saved_map << file_text + return saved_map + } + write_map(var/turf/t1 as turf, var/turf/t2 as turf, var/flags as num){ + //Check for valid turfs. + if(!isturf(t1) || !isturf(t2)){ + CRASH("Invalid arguments supplied to proc write_map, arguments were not turfs.") + } + var/turf/nw = locate(min(t1.x,t2.x),max(t1.y,t2.y),min(t1.z,t2.z)) + var/turf/se = locate(max(t1.x,t2.x),min(t1.y,t2.y),max(t1.z,t2.z)) + var/list/templates[0] + var/template_buffer = {""} + var/dmm_text = {""} + for(var/pos_z=nw.z;pos_z<=se.z;pos_z++){ + for(var/pos_y=nw.y;pos_y>=se.y;pos_y--){ + for(var/pos_x=nw.x;pos_x<=se.x;pos_x++){ + var/turf/test_turf = locate(pos_x,pos_y,pos_z) + var/test_template = make_template(test_turf, flags) + var/template_number = templates.Find(test_template) + if(!template_number){ + templates.Add(test_template) + template_number = templates.len + } + template_buffer += "[template_number]," + } + template_buffer += ";" + } + template_buffer += "." + } + var/key_length = round/*floor*/(log(letter_digits.len,templates.len-1)+1) + var/list/keys[templates.len] + for(var/key_pos=1;key_pos<=templates.len;key_pos++){ + keys[key_pos] = get_model_key(key_pos,key_length) + dmm_text += {""[keys[key_pos]]" = ([templates[key_pos]])\n"} + } + var/z_level = 0 + for(var/z_pos=1;TRUE;z_pos=findtext(template_buffer,".",z_pos)+1){ + if(z_pos>=length(template_buffer)){break} + if(z_level){dmm_text+={"\n"}} + dmm_text += {"\n(1,1,[++z_level]) = {"\n"} + var/z_block = copytext(template_buffer,z_pos,findtext(template_buffer,".",z_pos)) + for(var/y_pos=1;TRUE;y_pos=findtext(z_block,";",y_pos)+1){ + if(y_pos>=length(z_block)){break} + var/y_block = copytext(z_block,y_pos,findtext(z_block,";",y_pos)) + for(var/x_pos=1;TRUE;x_pos=findtext(y_block,",",x_pos)+1){ + if(x_pos>=length(y_block)){break} + var/x_block = copytext(y_block,x_pos,findtext(y_block,",",x_pos)) + var/key_number = text2num(x_block) + var/temp_key = keys[key_number] + dmm_text += temp_key + sleep(-1) + } + dmm_text += {"\n"} + sleep(-1) + } + dmm_text += {"\"}"} + sleep(-1) + } + return dmm_text + } + proc{ + make_template(var/turf/model as turf, var/flags as num){ + var/template = "" + var/obj_template = "" + var/mob_template = "" + var/turf_template = "" + if(!(flags & DMM_IGNORE_TURFS)){ + turf_template = "[model.type][check_attributes(model)]," + } else{ turf_template = "[world.turf],"} + var/area_template = "" + if(!(flags & DMM_IGNORE_OBJS)){ + for(var/obj/O in model.contents){ + obj_template += "[O.type][check_attributes(O)]," + } + } + for(var/mob/M in model.contents){ + if(M.client){ + if(!(flags & DMM_IGNORE_PLAYERS)){ + mob_template += "[M.type][check_attributes(M)]," + } + } + else{ + if(!(flags & DMM_IGNORE_NPCS)){ + mob_template += "[M.type][check_attributes(M)]," + } + } + } + if(!(flags & DMM_IGNORE_AREAS)){ + var/area/m_area = model.loc + area_template = "[m_area.type][check_attributes(m_area)]" + } else{ area_template = "[world.area]"} + template = "[obj_template][mob_template][turf_template][area_template]" + return template + } + check_attributes(var/atom/A){ + var/attributes_text = {"{"} + for(var/V in A.vars){ + sleep(-1) + if((!issaved(A.vars[V])) || (A.vars[V]==initial(A.vars[V]))){continue} + if(istext(A.vars[V])){ + attributes_text += {"[V] = "[A.vars[V]]""} + } + else if(isnum(A.vars[V])||ispath(A.vars[V])){ + attributes_text += {"[V] = [A.vars[V]]"} + } + else if(isicon(A.vars[V])||isfile(A.vars[V])){ + attributes_text += {"[V] = '[A.vars[V]]'"} + } + else{ + continue + } + if(attributes_text != {"{"}){ + attributes_text+={"; "} + } + } + if(attributes_text=={"{"}){ + return + } + if(copytext(attributes_text, length(attributes_text)-1, 0) == {"; "}){ + attributes_text = copytext(attributes_text, 1, length(attributes_text)-1) + } + attributes_text += {"}"} + return attributes_text + } + get_model_key(var/which as num, var/key_length as num){ + var/key = "" + var/working_digit = which-1 + for(var/digit_pos=key_length;digit_pos>=1;digit_pos--){ + var/place_value = round/*floor*/(working_digit/(letter_digits.len**(digit_pos-1))) + working_digit-=place_value*(letter_digits.len**(digit_pos-1)) + key = "[key][letter_digits[place_value+1]]" + } + return key + } + } + } \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm index 446f0686321..64274d21912 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm @@ -11,6 +11,7 @@ src.stand_icon = new /icon('alien.dmi', "aliend_s") src.lying_icon = new /icon('alien.dmi', "aliend_l") src.resting_icon = new /icon('alien.dmi', "aliend_sleep") + src.running_icon = new /icon('alien.dmi', "aliend_running") src.icon = src.stand_icon update_clothing() src << "\blue Your icons have been generated!" diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm index 7c7e5eaedf6..99b1d054a87 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm @@ -10,6 +10,7 @@ src.stand_icon = new /icon('alien.dmi', "alienh_s") src.lying_icon = new /icon('alien.dmi', "alienh_l") src.resting_icon = new /icon('alien.dmi', "alienh_sleep") + src.running_icon = new /icon('alien.dmi', "alienh_running") src.icon = src.stand_icon update_clothing() src << "\blue Your icons have been generated!" diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/sentinel.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/sentinel.dm index ecc3b459e68..3c824954f4f 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/caste/sentinel.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/caste/sentinel.dm @@ -10,6 +10,7 @@ src.stand_icon = new /icon('alien.dmi', "aliens_s") src.lying_icon = new /icon('alien.dmi', "aliens_l") src.resting_icon = new /icon('alien.dmi', "aliens_sleep") + src.running_icon = new /icon('alien.dmi', "aliens_running") src.icon = src.stand_icon update_clothing() src << "\blue Your icons have been generated!" diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm index 52fd1b1ac25..8dff96afd79 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm @@ -11,6 +11,7 @@ stand_icon = new /icon('alien.dmi', "alien_s") lying_icon = new /icon('alien.dmi', "alien_l") resting_icon = new /icon('alien.dmi', "alienh_sleep") + running_icon = new /icon('alien.dmi', "alienh_running") icon = stand_icon update_clothing() src << "\blue Your icons have been generated!" @@ -336,6 +337,13 @@ else icon = resting_icon + else if(!lying) + if(update_icon) + if(m_intent == "run") + icon = running_icon + else + icon = stand_icon + overlays += body_lying if (face_lying) diff --git a/code/modules/mob/living/carbon/alien/humanoid/queen.dm b/code/modules/mob/living/carbon/alien/humanoid/queen.dm index 0fe1620a7a1..278220933eb 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/queen.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/queen.dm @@ -12,6 +12,8 @@ src.verbs -= /mob/living/carbon/alien/humanoid/verb/ventcrawl src.stand_icon = new /icon('alien.dmi', "queen_s") src.lying_icon = new /icon('alien.dmi', "queen_l") + src.resting_icon = new /icon('alien.dmi', "queen_sleep") + src.running_icon = new /icon('alien.dmi', "queen_running") src.icon = src.stand_icon update_clothing() src << "\blue Your icons have been generated!" diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index c5245daa4f3..a2599014cd9 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -102,8 +102,11 @@ /mob/living/carbon/human/proc/ChangeToHusk() if(mutations & HUSK) return + var/datum/organ/external/head/head = get_organ("head") + if(head) + head.disfigured = 1 + name = get_visible_name() mutations |= HUSK - real_name = "Unknown" update_body() return diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 4ac8972b60c..0e6d660e76d 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1189,37 +1189,8 @@ overlays += image("icon" = 'belt.dmi', "icon_state" = text("[][]", t1, (!( lying ) ? null : "2")), "layer" = MOB_LAYER) belt.screen_loc = ui_belt - if ((wear_mask && !(wear_mask.see_face)) || (head && !(head.see_face))) // can't see the face - if (wear_id) - if (istype(wear_id, /obj/item/weapon/card/id)) - var/obj/item/weapon/card/id/id = wear_id - if (id.registered_name) - name = id.registered_name - else - name = "Unknown" - else if (istype(wear_id, /obj/item/device/pda)) - var/obj/item/device/pda/pda = wear_id - if (pda.owner) - name = pda.owner - else - name = "Unknown" - else - name = "Unknown" - else - if (wear_id) - if (istype(wear_id, /obj/item/weapon/card/id)) - var/obj/item/weapon/card/id/id = wear_id - if (id.registered_name != real_name) - name = "[real_name] (as [id.registered_name])" - - else if (istype(wear_id, /obj/item/device/pda)) - var/obj/item/device/pda/pda = wear_id - if (pda.owner) - if (pda.owner != real_name) - name = "[real_name] (as [pda.owner])" - else - name = real_name + name = get_visible_name() if (wear_id) wear_id.screen_loc = ui_id @@ -2364,18 +2335,33 @@ It can still be worn/put on as normal. return if_no_id return +//repurposed proc. Now it combines get_id_name() and get_face_name() to determine a mob's name variable. Made into a seperate proc as it'll be useful elsewhere +/mob/living/carbon/human/proc/get_visible_name() + if ((wear_mask && !(wear_mask.see_face)) || (head && !(head.see_face))) // can't see their face + return get_id_name("Unknown") + else + var/face_name = get_face_name() + var/id_name = get_id_name("") + if(id_name && (id_name != face_name)) + return "[face_name] as ([id_name])" + return face_name + +//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/datum/organ/external/head/head = get_organ("head") + if(!head || head.disfigured) //no face! + return "Unknown" + else + return "[real_name]" + //gets name from ID or PDA itself, ID inside PDA doesn't matter //Useful when player is being seen by other mobs -/mob/living/carbon/human/proc/get_visible_name(var/if_no_id = "Unknown") +/mob/living/carbon/human/proc/get_id_name(var/if_no_id = "Unknown") var/obj/item/device/pda/pda = wear_id var/obj/item/weapon/card/id/id = wear_id - if (istype(pda)) - . = pda.owner - else if (istype(id)) - . = id.registered_name - else - return if_no_id - return + if(istype(pda)) return pda.owner + if(istype(id)) return id.registered_name + return if_no_id //gets ID card object from special clothes slot or null. /mob/living/carbon/human/proc/get_idcard() diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index b674bc2b990..bfa163f82e6 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -1,3 +1,13 @@ +//Instead of setting real_name = "Unknown", use this when necessary. +//It will prevent the cloned-as-unknown bug and various other derpy things. +/mob/living/carbon/human/proc/disfigure_face() + var/datum/organ/external/head/head = get_organ("head") + if(head && !head.disfigured) + head.disfigured = 1 + name = get_visible_name() + src << "\red Your face has become disfigured." + warn_flavor_changed() + /mob/living/carbon/human/proc/HealDamage(zone, brute, burn) var/datum/organ/external/E = get_organ(zone) if(istype(E, /datum/organ/external)) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 9ffbb5dc451..df20678c13d 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -37,7 +37,7 @@ emp_act if(check_shields(P.damage, "the [P.name]")) P.on_hit(src, 2) return 2 - return (..()) + return (..(P , def_zone)) /mob/living/carbon/human/getarmor(var/def_zone, var/type) diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 1d5156013d2..167ec30586e 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -1021,15 +1021,14 @@ if (stuttering) stuttering-- if (slurring) slurring-- + //Carn: marker 4# var/datum/organ/external/head/head = organs["head"] if(head && !head.disfigured) if(head.brute_dam >= 45 || head.burn_dam >= 45) - head.disfigured = 1 emote("scream") - real_name = "Unknown" - src << "\red Your face has become disfigured." + disfigure_face() face_op_stage = 0.0 - warn_flavor_changed() + var/blood_max = 0 for(var/name in organs) var/datum/organ/external/temp = organs[name] diff --git a/code/modules/mob/living/carbon/human/whisper.dm b/code/modules/mob/living/carbon/human/whisper.dm index 3e79062b3f5..2d5f675b973 100644 --- a/code/modules/mob/living/carbon/human/whisper.dm +++ b/code/modules/mob/living/carbon/human/whisper.dm @@ -20,7 +20,7 @@ var/alt_name = "" if (istype(src, /mob/living/carbon/human) && src.name != src.real_name) var/mob/living/carbon/human/H = src - alt_name = " (as [H.get_visible_name()])" + alt_name = " (as [H.get_id_name("Unknown")])" // Mute disability if (src.disabilities & 64) return diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index bbcbfcbf577..3e1ea272e47 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -217,12 +217,11 @@ SetParalysis(0) SetStunned(0) SetWeakened(0) + src.radiation = 0 + src.nutrition = 400 + src.bodytemperature = initial(src.bodytemperature) //src.health = 100 if(ishuman(src)) - src.radiation = 0 - //M.health = 100 - src.nutrition = 400 - src.bodytemperature = initial(src.bodytemperature) src.heal_overall_damage(1000, 1000) //M.updatehealth() src.buckled = initial(src.buckled) diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 3c4a44e8a42..6aac5e6ab71 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -67,7 +67,7 @@ var/alt_name = "" if (istype(src, /mob/living/carbon/human) && name != real_name) var/mob/living/carbon/human/H = src - alt_name = " (as [H.get_visible_name()])" + alt_name = " (as [H.get_id_name("Unknown")])" var/italics = 0 var/message_range = null var/message_mode = null diff --git a/code/modules/mob/living/silicon/ai/say.dm b/code/modules/mob/living/silicon/ai/say.dm index fdd3b9f4ec7..6be4b474d9e 100644 --- a/code/modules/mob/living/silicon/ai/say.dm +++ b/code/modules/mob/living/silicon/ai/say.dm @@ -12,6 +12,10 @@ return 1 if (istype(other, /mob/living/silicon/decoy)) return 1 + if (istype(other, /mob/living/carbon/brain)) + return 1 + if (istype(other, /mob/living/silicon/pai)) + return 1 return ..() /mob/living/silicon/ai/say_quote(var/text) diff --git a/code/modules/mob/living/silicon/pai/recruit.dm b/code/modules/mob/living/silicon/pai/recruit.dm index 32aa0cc312d..8f238e23135 100644 --- a/code/modules/mob/living/silicon/pai/recruit.dm +++ b/code/modules/mob/living/silicon/pai/recruit.dm @@ -205,13 +205,16 @@ var/datum/paiController/paiController // Global handler for pAI candidates if(c.key == O.key) hasSubmitted = 1 if(!hasSubmitted && O.client.be_pai) - spawn question(O.client, origin) + question(O.client) - proc/question(var/client/C, var/mob/origin) - asked.Add(C.key) - asked[C.key] = world.time - var/response = alert(C, "[origin] is requesting a pAI personality. Would you like to play as a personal AI?", "pAI Request", "Yes", "No", "Never for this round") - if(response == "Yes") - recruitWindow(C.mob) - else if (response == "Never for this round") - C.be_pai = 0 \ No newline at end of file + proc/question(var/client/C) + spawn(0) + if(!C) return + asked.Add(C.key) + asked[C.key] = world.time + var/response = alert(C, "Someone is requesting a pAI personality. Would you like to play as a personal AI?", "pAI Request", "Yes", "No", "Never for this round") + if(!C) return //handle logouts that happen whilst the alert is waiting for a response. + if(response == "Yes") + recruitWindow(C.mob) + else if (response == "Never for this round") + C.be_pai = 0 \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/login.dm b/code/modules/mob/living/silicon/robot/login.dm index 9e2b24457df..1127d6bebb7 100644 --- a/code/modules/mob/living/silicon/robot/login.dm +++ b/code/modules/mob/living/silicon/robot/login.dm @@ -13,9 +13,10 @@ src.real_name += " " src.real_name += "-[ident]" src.name = src.real_name - if(!src.connected_ai) + /*if(!src.connected_ai) for(var/mob/living/silicon/ai/A in world) src.connected_ai = A A.connected_robots += src break + */ return \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/say.dm b/code/modules/mob/living/silicon/robot/say.dm index 97172a91391..f71a96a9d94 100644 --- a/code/modules/mob/living/silicon/robot/say.dm +++ b/code/modules/mob/living/silicon/robot/say.dm @@ -5,6 +5,10 @@ return 1 if (istype(other, /mob/living/carbon/human)) return 1 + if (istype(other, /mob/living/carbon/brain)) + return 1 + if (istype(other, /mob/living/silicon/pai)) + return 1 // if (istype(other, /mob/living/silicon/hivebot)) // return 1 return ..() diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 9bce3bbbf27..2390906c92f 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -621,22 +621,7 @@ if(src:cameraFollow) src:cameraFollow = null - -/client/Topic(href, href_list) - if(href_list["priv_msg"]) - var/client/C = locate(href_list["priv_msg"]) - if(ismob(C)) //Old stuff can pass in mobs instead of clients - var/mob/M = C - C = M.client - cmd_admin_pm(C,null) - else - ..() - /mob/Topic(href, href_list) - if(href_list["priv_msg"]) //for priv_msg references that have yet to be updated to target clients. Forwards it to client/Topic() - if(client) - client.Topic(href, href_list) - if(href_list["mach_close"]) var/t1 = text("window=[href_list["mach_close"]]") machine = null @@ -685,7 +670,7 @@ onclose(usr, "[name]") if(href_list["flavor_change"]) update_flavor_text() - ..() +// ..() return /mob/proc/get_damage() @@ -713,6 +698,19 @@ if ( !usr || usr==src || !istype(src.loc,/turf) ) //if there's no person pulling OR the person is pulling themself OR the object being pulled is inside something: abort! return + + if(ishuman(usr)) + if(usr.hand) // if he's using his left hand. + var/datum/organ/external/temp = usr:get_organ("l_hand") + if(temp.destroyed) + usr << "\blue You look at your stump." + return + else + var/datum/organ/external/temp = usr:get_organ("r_hand") + if(temp.destroyed) + usr << "\blue You look at your stump." + return + if (!( anchored )) usr.pulling = src if(ismob(src)) diff --git a/code/modules/mob/simple_animal/life.dm b/code/modules/mob/simple_animal/life.dm index fea5278ddbc..f10a1a473b6 100644 --- a/code/modules/mob/simple_animal/life.dm +++ b/code/modules/mob/simple_animal/life.dm @@ -352,3 +352,18 @@ stat = DEAD density = 0 return + +/mob/living/simple_animal/ex_act(severity) + flick("flash", flash) + switch (severity) + if (1.0) + health -= 500 + gib() + return + + if (2.0) + health -= 60 + + + if(3.0) + health -= 30 \ No newline at end of file diff --git a/code/modules/paperwork/handlabeler.dm b/code/modules/paperwork/handlabeler.dm index 41b4242c5d1..20d59e1e777 100644 --- a/code/modules/paperwork/handlabeler.dm +++ b/code/modules/paperwork/handlabeler.dm @@ -40,7 +40,7 @@ if(mode) usr << "\blue You turn on the hand labeler." //Now let them chose the text. - var/str = input(usr,"Label text?","Set label","") + var/str = reject_bad_text(input(usr,"Label text?","Set label","")) //sanitize stuff! GOD DAMN THIS IS A SECURITY HOLE if(!str || !length(str)) usr << "\red Invalid text." return diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm index c78517f3870..41074362513 100644 --- a/code/modules/power/power.dm +++ b/code/modules/power/power.dm @@ -31,7 +31,7 @@ if(!A || !isarea(A) || !A.master) return 0 // if not, then not powered - return A.master.powered(chan) // return power status of the area + return A.master.powered(power_channel) // return power status of the area // increment the power usage stats for an area diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index a7dccbcf285..d2abc52d7be 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -1,5 +1,5 @@ /obj/item/weapon/gun - name = "\improper Gun" + name = "gun" desc = "Its a gun. It's pretty terrible, though." icon = 'gun.dmi' icon_state = "detective" diff --git a/html/changelog.html b/html/changelog.html index 0f82d4f3064..384ad5473e2 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -47,6 +47,25 @@ Stuff which is in development and not yet visible to players or just code relate should be listed in the changelog upon commit though. Thanks. --> +
+

10 May 2012

+

TG updated:

+
    +
  • New drinks recipes!
  • +
  • Different types of cigarettes added to contraband ordering.
  • +
  • Emergency Toolboxes now contain smaller, lighter fire extinguishers that actually fit inside them!
  • +
  • AIs and Cyborgs can now understand PAIs and MMIs.
  • +
  • Adminwho now shows admin ranks.
  • +
  • You can't pull things with missing hands anymore.
  • +
  • Nuke ops now spawn with an extended oxygen tanks.
  • +
  • Botany leather gloves can now remove lights without burning yourself.
  • +
  • New xeno sprites when running.
  • +
  • Piano is now a Minimoog!
  • +
  • Switched back to oldbody bag sprites.
  • +
  • New Oddyseus destroyed sprites.
  • +
+
+

07 May 2012

TG updated:

diff --git a/icons/mecha/mecha.dmi b/icons/mecha/mecha.dmi index fc34fc30a02..2a66ef4b64f 100644 Binary files a/icons/mecha/mecha.dmi and b/icons/mecha/mecha.dmi differ diff --git a/icons/mob/alien.dmi b/icons/mob/alien.dmi index 1efa862fdc3..261e1ed1253 100644 Binary files a/icons/mob/alien.dmi and b/icons/mob/alien.dmi differ diff --git a/icons/mob/items_lefthand.dmi b/icons/mob/items_lefthand.dmi index e25a53373b8..0ebbdef1e77 100644 Binary files a/icons/mob/items_lefthand.dmi and b/icons/mob/items_lefthand.dmi differ diff --git a/icons/mob/items_righthand.dmi b/icons/mob/items_righthand.dmi index 906ea0a9e13..a245cdc16c5 100644 Binary files a/icons/mob/items_righthand.dmi and b/icons/mob/items_righthand.dmi differ diff --git a/icons/mob/mob.dmi b/icons/mob/mob.dmi index 38752c9cb9b..c37fb23a2a7 100644 Binary files a/icons/mob/mob.dmi and b/icons/mob/mob.dmi differ diff --git a/icons/mob/uniform_fat.dmi b/icons/mob/uniform_fat.dmi index e47128fab57..4cd3669bf9f 100644 Binary files a/icons/mob/uniform_fat.dmi and b/icons/mob/uniform_fat.dmi differ diff --git a/icons/obj/bodybag.dmi b/icons/obj/bodybag.dmi index af173795f89..a1f99031280 100644 Binary files a/icons/obj/bodybag.dmi and b/icons/obj/bodybag.dmi differ diff --git a/icons/obj/cigarettes.dmi b/icons/obj/cigarettes.dmi index b24f0faef86..0acd19df4ff 100644 Binary files a/icons/obj/cigarettes.dmi and b/icons/obj/cigarettes.dmi differ diff --git a/icons/obj/clothing/masks.dmi b/icons/obj/clothing/masks.dmi index 2f3b58b99af..1485cd386d3 100644 Binary files a/icons/obj/clothing/masks.dmi and b/icons/obj/clothing/masks.dmi differ diff --git a/icons/obj/contraband.dmi b/icons/obj/contraband.dmi index d31dde2c514..1e30a2e609c 100644 Binary files a/icons/obj/contraband.dmi and b/icons/obj/contraband.dmi differ diff --git a/icons/obj/doors/mineral_doors.dmi b/icons/obj/doors/mineral_doors.dmi index 81c3b0e2e25..506a1e14605 100644 Binary files a/icons/obj/doors/mineral_doors.dmi and b/icons/obj/doors/mineral_doors.dmi differ diff --git a/icons/obj/drinks.dmi b/icons/obj/drinks.dmi index 119c475d015..4fee2a243c3 100644 Binary files a/icons/obj/drinks.dmi and b/icons/obj/drinks.dmi differ diff --git a/icons/obj/items.dmi b/icons/obj/items.dmi index 7ba4ecf601d..303f54015ed 100644 Binary files a/icons/obj/items.dmi and b/icons/obj/items.dmi differ diff --git a/icons/turf/floors.dmi b/icons/turf/floors.dmi index a142b57ea99..3808addbeec 100644 Binary files a/icons/turf/floors.dmi and b/icons/turf/floors.dmi differ diff --git a/maps/RandomZLevels/assistantChamber.dmm b/maps/RandomZLevels/assistantChamber.dmm new file mode 100644 index 00000000000..d71885ff0c9 --- /dev/null +++ b/maps/RandomZLevels/assistantChamber.dmm @@ -0,0 +1,66 @@ +"a" = (/turf/space,/area) +"b" = (/turf/unsimulated/wall,/area) +"c" = (/obj/machinery/shield,/turf/simulated/wall/cult,/area/turret_protected/AssistantRoom) +"d" = (/obj/machinery/turret{dir = 8; lasers = 1; name = "Angry Turret"},/obj/machinery/light{dir = 1},/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"e" = (/obj/machinery/light{icon_state = "tube1"; dir = 8},/obj/machinery/turret{dir = 8; lasers = 1; name = "Angry Turret"},/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"f" = (/obj/item/weapon/gift,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"g" = (/obj/effect/accelerated_particle,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"h" = (/obj/item/weapon/gun/energy/gun/nuclear,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"i" = (/obj/item/device/soulstone,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"j" = (/obj/item/ammo_magazine,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"k" = (/obj/effect/rune,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"l" = (/obj/machinery/turret{dir = 8; lasers = 1; name = "Angry Turret"},/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"m" = (/obj/item/weapon/mousetrap/armed,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"n" = (/obj/item/weapon/nullrod,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"o" = (/obj/item/weapon/card/id/captains_spare,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"p" = (/obj/item/weapon/gun/energy/pulse_rifle/M1911,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"q" = (/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"r" = (/obj/item/weapon/card/emag,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"s" = (/obj/item/tk_grab,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"t" = (/obj/item/device/powersink,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"u" = (/obj/item/device/radio/beacon,/obj/item/weapon/caution,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"v" = (/obj/item/brain,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"w" = (/obj/item/weapon/gun/energy/laser/captain,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"x" = (/obj/item/weapon/gun/projectile/deagle/gold,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"y" = (/obj/item/weapon/sord,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"z" = (/obj/item/weapon/gun/energy/lasercannon,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"A" = (/obj/item/weapon/gun/energy/crossbow/largecrossbow,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"B" = (/obj/item/weapon/gun/energy/pulse_rifle/destroyer,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"C" = (/obj/item/toy/spinningtoy,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"D" = (/obj/item/weapon/card/id/centcom,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"E" = (/obj/item/weapon/gun/grenadelauncher,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"F" = (/obj/item/weapon/chemsprayer,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) +"G" = (/obj/machinery/turret{dir = 8; lasers = 1; name = "Angry Turret"},/obj/machinery/light,/turf/simulated/floor{icon_state = "whiteshiny"},/area/turret_protected/AssistantRoom) + +(1,1,1) = {" +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaabbbbbbbbbbbbaaaaaaaaa +aaaaaaaaabccccccccccbaaaaaaaaa +aaaaaaaaabccddddddccbaaaaaaaaa +aaaaaaaaabcefghijklcbaaaaaaaaa +aaaaaaaaabcemnopqrlcbaaaaaaaaa +aaaaaaaaabcestquvqlcbaaaaaaaaa +aaaaaaaaabcewqqxqylcbaaaaaaaaa +aaaaaaaaabceqzAqBqlcbaaaaaaaaa +aaaaaaaaabceCqDqEFlcbaaaaaaaaa +aaaaaaaaabccGGGGGGccbaaaaaaaaa +aaaaaaaaabccccccccccbaaaaaaaaa +aaaaaaaaabbbbbbbbbbbbaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +"} diff --git a/maps/RandomZLevels/fileList.txt b/maps/RandomZLevels/fileList.txt new file mode 100644 index 00000000000..d1aaec57726 --- /dev/null +++ b/maps/RandomZLevels/fileList.txt @@ -0,0 +1,8 @@ +#List the potential random Z-levels here. +#Maps must be the full path to them +#Maps should be 255x255 or smaller and be bounded. Falling off the edge of the map will result in undefined behavior. +#Please ensure that your maps have a minimum distnace from the edge of 10 units, due to 'seamless transition' range +#SPECIFYING AN INVALID MAP WILL RESULT IN RUNTIMES ON GAME START + +#maps/RandomZLevels/assistantChamber.dmm + diff --git a/maps/tgstation.2.0.8.dmm b/maps/tgstation.2.0.8.dmm index e9cabe85c5a..0d131c05b5d 100755 --- a/maps/tgstation.2.0.8.dmm +++ b/maps/tgstation.2.0.8.dmm @@ -4586,7 +4586,7 @@ "bKj" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/turf/simulated/wall/r_wall,/area/toxins/xenobiology) "bKk" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/obj/structure/closet/secure_closet/scientist,/turf/simulated/floor{icon_state = "white"},/area/toxins/xenobiology) "bKl" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/obj/machinery/light{dir = 1},/obj/structure/closet/l3closet/scientist,/turf/simulated/floor{icon_state = "white"},/area/toxins/xenobiology) -"bKm" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/obj/machinery/computer/operating{id = "xenobio"; name = "Xenobiology Operating Computer"},/turf/simulated/floor{icon_state = "white"},/area/toxins/xenobiology) +"bKm" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/obj/machinery/computer/operating,/turf/simulated/floor{icon_state = "white"},/area/toxins/xenobiology) "bKn" = (/obj/structure/table,/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/obj/machinery/light{dir = 1},/obj/item/weapon/circular_saw,/turf/simulated/floor{icon_state = "white"},/area/toxins/xenobiology) "bKo" = (/obj/structure/table,/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/obj/item/weapon/scalpel,/turf/simulated/floor{icon_state = "white"},/area/toxins/xenobiology) "bKp" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 8; on = 1},/turf/simulated/floor{icon_state = "white"},/area/toxins/xenobiology) @@ -4647,7 +4647,7 @@ "bLs" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0; tag = "Streight"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/obj/effect/sign/biohazard{pixel_x = 28},/turf/simulated/floor{icon_state = "white"},/area/medical/research{name = "Research Division"}) "bLt" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -22},/turf/simulated/floor{icon_state = "white"},/area/toxins/xenobiology) "bLu" = (/obj/effect/landmark/start{name = "Scientist"},/turf/simulated/floor{icon_state = "white"},/area/toxins/xenobiology) -"bLv" = (/obj/machinery/optable{id = "xenobio"; name = "Xenobiology Operating Table"},/turf/simulated/floor{icon_state = "white"},/area/toxins/xenobiology) +"bLv" = (/obj/machinery/optable,/turf/simulated/floor{icon_state = "white"},/area/toxins/xenobiology) "bLw" = (/obj/structure/table,/obj/item/clothing/suit/straight_jacket,/obj/item/clothing/mask/muzzle,/turf/simulated/floor{icon_state = "white"},/area/toxins/xenobiology) "bLx" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/turf/simulated/floor/plating,/area/toxins/xenobiology) "bLy" = (/obj/machinery/door/window/southleft{name = "Monkey Pen"; req_access_txt = "55"},/turf/simulated/floor{icon_state = "white"},/area/toxins/xenobiology) @@ -4700,7 +4700,7 @@ "bMt" = (/obj/structure/stool/bed/chair{dir = 4},/obj/machinery/light{dir = 1},/turf/simulated/floor{icon_state = "dark"},/area/medical/surgery) "bMu" = (/obj/structure/grille,/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id = "Observation Shutters"; name = "Observation Shutters"; opacity = 0},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 1},/obj/machinery/atmospherics/pipe/simple/supply/hidden,/turf/simulated/floor/plating,/area/medical/surgery) "bMv" = (/obj/structure/table,/obj/item/weapon/hemostat,/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/turf/simulated/floor{icon_state = "white"},/area/medical/surgery) -"bMw" = (/obj/machinery/computer/operating{id = "medbay"},/obj/machinery/light{dir = 1},/obj/machinery/camera{c_tag = "Operating Theatre"; dir = 2; network = "Medbay"; pixel_x = 22},/turf/simulated/floor{icon_state = "white"},/area/medical/surgery) +"bMw" = (/obj/machinery/light{dir = 1},/obj/machinery/camera{c_tag = "Operating Theatre"; dir = 2; network = "Medbay"; pixel_x = 22},/obj/machinery/computer/operating,/turf/simulated/floor{icon_state = "white"},/area/medical/surgery) "bMx" = (/obj/machinery/door_control{id = "Observation Shutters"; name = "Observation Shutter Control"; pixel_y = 25},/turf/simulated/floor{icon_state = "white"},/area/medical/surgery) "bMy" = (/obj/structure/table,/obj/item/clothing/glasses/hud/health,/obj/item/clothing/glasses/hud/health,/obj/item/clothing/glasses/hud/health,/obj/item/clothing/glasses/hud/health,/obj/item/clothing/glasses/hud/health,/turf/simulated/floor{icon_state = "white"},/area/medical/surgery) "bMz" = (/obj/machinery/atmospherics/pipe/simple,/turf/simulated/wall/r_wall,/area/toxins/server) @@ -4762,63 +4762,63 @@ "bND" = (/obj/structure/grille,/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id = "Observation Shutters"; name = "Observation Shutters"; opacity = 0},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/obj/machinery/atmospherics/pipe/simple/supply/hidden,/turf/simulated/floor/plating,/area/medical/surgery) "bNE" = (/obj/structure/table,/obj/machinery/atmospherics/pipe/manifold{color = "red"; icon_state = "manifold-r-f"; level = 1; name = "pipe manifold"},/obj/item/weapon/scalpel,/obj/item/weapon/autopsy_scanner,/turf/simulated/floor{icon_state = "white"},/area/medical/surgery) "bNF" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/turf/simulated/floor{icon_state = "white"},/area/medical/surgery) -"bNG" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 10},/turf/simulated/floor{icon_state = "white"},/area/medical/surgery) -"bNH" = (/obj/structure/table,/obj/item/weapon/circular_saw,/turf/simulated/floor{icon_state = "white"},/area/medical/surgery) -"bNI" = (/obj/machinery/r_n_d/server{id_with_download_string = "1"; id_with_upload_string = "1"; name = "Core R&D Server"; server_id = 1},/obj/machinery/atmospherics/pipe/simple,/turf/simulated/floor/grid{name = "Server Base"; nitrogen = 500; oxygen = 0; temperature = 80},/area/toxins/server) -"bNJ" = (/turf/simulated/floor/grid{name = "Server Base"; nitrogen = 500; oxygen = 0; temperature = 80},/area/toxins/server) -"bNK" = (/obj/machinery/camera{c_tag = "Server Room"; dir = 2; network = "Research"},/turf/simulated/floor/grid{name = "Server Base"; nitrogen = 500; oxygen = 0; temperature = 80},/area/toxins/server) -"bNL" = (/obj/machinery/blackbox_recorder,/obj/machinery/atmospherics/pipe/simple,/turf/simulated/floor/grid{name = "Server Base"; nitrogen = 500; oxygen = 0; temperature = 80},/area/toxins/server) -"bNM" = (/obj/structure/disposalpipe/segment{dir = 1},/obj/item/device/radio/intercom{dir = 8; name = "Station Intercom (General)"; pixel_x = -28},/obj/machinery/atmospherics/pipe/manifold{color = "blue"; dir = 8; icon_state = "manifold-b-f"; level = 1; name = "pipe manifold"},/turf/simulated/floor{icon_state = "white"},/area/medical/research{name = "Research Division"}) -"bNN" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/obj/effect/sign/biohazard{pixel_x = 28},/turf/simulated/floor{icon_state = "white"},/area/medical/research{name = "Research Division"}) -"bNO" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 8; on = 1},/obj/machinery/requests_console{department = "Xenobiology"; departmentType = 0; pixel_x = -30; pixel_y = 0},/turf/simulated/floor{icon_state = "white"},/area/toxins/xenobiology) -"bNP" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0; tag = "Streight"},/turf/simulated/floor{icon_state = "white"},/area/toxins/xenobiology) -"bNQ" = (/obj/structure/stool/bed/chair,/turf/simulated/floor{icon_state = "white"},/area/toxins/xenobiology) -"bNR" = (/obj/machinery/atmospherics/valve,/turf/simulated/floor{icon_state = "white"},/area/toxins/xenobiology) -"bNS" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk,/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor{icon_state = "white"},/area/toxins/xenobiology) -"bNT" = (/obj/machinery/mass_driver{dir = 4; id = "toxinsdriver"},/turf/simulated/floor/plating,/area/toxins/observatory) -"bNU" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/plating,/area/toxins/observatory) -"bNV" = (/turf/simulated/floor/plating,/area/toxins/observatory) -"bNW" = (/obj/machinery/door/poddoor{id = "toxinsdriver"; name = "Toxins Launcher Bay Door"},/turf/simulated/floor/plating,/area/toxins/observatory) -"bNX" = (/obj/machinery/door/poddoor{id = "toxinsdriver"; name = "Toxins Launcher Bay Door"},/turf/space,/area/toxins/test_area) -"bNY" = (/obj/item/device/radio/beacon,/turf/simulated/floor/airless{icon_state = "bot"},/area/toxins/test_area) -"bNZ" = (/obj/machinery/camera{c_tag = "East"; dir = 8; network = "Bomb Testing"; pixel_x = 0; pixel_y = -22},/obj/machinery/light/spot{dir = 4; layer = 2.8},/turf/simulated/floor/airless,/area/toxins/test_area) -"bOa" = (/obj/machinery/atmospherics/pipe/simple{dir = 4},/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 1},/turf/simulated/floor/plating,/area/maintenance/apmaint) -"bOb" = (/turf/simulated/wall,/area/assembly/chargebay) -"bOc" = (/obj/machinery/recharge_station,/obj/machinery/atmospherics/pipe/simple/supply/hidden,/turf/simulated/floor{icon_state = "bot"},/area/assembly/chargebay) -"bOd" = (/obj/machinery/recharge_station,/turf/simulated/floor{icon_state = "bot"},/area/assembly/chargebay) -"bOe" = (/obj/machinery/door/airlock/maintenance{name = "Assembly Line Maintenance"; req_access_txt = "12;29"},/turf/simulated/floor/plating,/area/maintenance/apmaint) -"bOf" = (/obj/effect/showcase{icon_state = "showcase_3"},/turf/simulated/floor{icon_state = "showroomfloor"},/area/assembly/chargebay) -"bOg" = (/obj/machinery/light,/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/turf/simulated/floor/plating,/area/assembly/chargebay) -"bOh" = (/obj/machinery/atmospherics/portables_connector{dir = 4},/obj/structure/window/reinforced{dir = 1},/obj/machinery/portable_atmospherics/pump,/turf/simulated/floor{icon_state = "arrival"; dir = 8},/area/hallway/primary/aft) -"bOi" = (/obj/machinery/atmospherics/pipe/simple{color = "cyan"; dir = 10; icon_state = "intact-c"; initialize_directions = 10; level = 2},/turf/simulated/wall,/area/maintenance/asmaint) -"bOj" = (/obj/structure/closet/secure_closet/atmos_personal,/obj/machinery/light/small,/turf/simulated/floor,/area/atmos) -"bOk" = (/obj/structure/closet/wardrobe/atmospherics_yellow,/turf/simulated/floor,/area/atmos) -"bOl" = (/obj/machinery/vending/coffee,/turf/simulated/floor,/area/atmos) -"bOm" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor{dir = 10; icon_state = "warning"},/area/atmos) -"bOn" = (/obj/machinery/portable_atmospherics/canister/carbon_dioxide,/turf/simulated/floor{icon_state = "warning"},/area/atmos) -"bOo" = (/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/simulated/floor{icon_state = "warning"},/area/atmos) -"bOp" = (/obj/machinery/portable_atmospherics/canister/air,/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor{dir = 6; icon_state = "warning"},/area/atmos) -"bOq" = (/obj/machinery/light,/turf/simulated/floor,/area/atmos) -"bOr" = (/obj/machinery/atmospherics/binary/pump{dir = 1; icon_state = "intact_off"; name = "Emergency Tank Fill"; on = 0},/turf/simulated/floor,/area/atmos) -"bOs" = (/obj/machinery/atmospherics/pipe/simple{dir = 6; icon_state = "intact"; initialize_directions = 6; level = 2},/obj/machinery/meter,/turf/simulated/floor,/area/atmos) -"bOt" = (/obj/machinery/atmospherics/pipe/simple{color = "yellow"; icon_state = "intact-y"; level = 2},/obj/machinery/atmospherics/pipe/simple{dir = 4; icon_state = "intact"; level = 2},/turf/simulated/floor,/area/atmos) -"bOu" = (/obj/machinery/atmospherics/pipe/simple{color = "green"; icon_state = "intact-g"; level = 2},/obj/machinery/atmospherics/pipe/simple{dir = 4; icon_state = "intact"; level = 2},/turf/simulated/floor,/area/atmos) -"bOv" = (/obj/machinery/atmospherics/tvalve/digital{dir = 8; icon_state = "tvalve1"; state = 1; tag = "icon-tvalve0 (WEST)"},/turf/simulated/floor,/area/atmos) -"bOw" = (/obj/machinery/atmospherics/valve/digital{color = "yellow"; dir = 4; name = "Gas Mix Outlet Valve"},/turf/simulated/floor{icon_state = "green"; dir = 6},/area/atmos) -"bOx" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/atmospherics/pipe/simple{color = "yellow"; dir = 4; icon_state = "intact-y"; initialize_directions = 12; level = 2},/turf/simulated/floor/plating,/area/atmos) -"bOy" = (/obj/machinery/atmospherics/pipe/simple{color = "yellow"; dir = 4; icon_state = "intact-y"; initialize_directions = 12; level = 2},/obj/structure/grille,/turf/simulated/wall,/area) -"bOz" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 8; external_pressure_bound = 0; frequency = 1441; icon_state = "in"; id_tag = "waste_out"; initialize_directions = 1; internal_pressure_bound = 4000; on = 1; pressure_checks = 2; pump_direction = 0},/turf/simulated/floor/engine{name = "vacuum floor"; nitrogen = 0.01; oxygen = 0.01},/area/atmos) -"bOA" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden,/obj/machinery/light/small{dir = 4},/turf/simulated/wall,/area/medical/cmo) -"bOB" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -22},/turf/simulated/floor{dir = 8; icon_state = "barber"},/area/medical/cmo) -"bOC" = (/obj/structure/stool/bed/chair{dir = 1},/turf/simulated/floor{dir = 8; icon_state = "barber"},/area/medical/cmo) -"bOD" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/turf/simulated/floor/plating,/area/medical/cmo) -"bOE" = (/obj/machinery/atmospherics/unary/vent_pump{on = 1},/turf/simulated/floor{icon_state = "white"},/area/medical/medbay) -"bOF" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/door/airlock/medical{name = "Surgery Observation"; req_access_txt = "5"},/turf/simulated/floor{icon_state = "dark"},/area/medical/surgery) -"bOG" = (/obj/machinery/hologram/holopad,/turf/simulated/floor{icon_state = "dark"},/area/medical/surgery) -"bOH" = (/obj/structure/stool/bed/chair{dir = 4},/turf/simulated/floor{icon_state = "dark"},/area/medical/surgery) -"bOI" = (/obj/structure/grille,/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id = "Observation Shutters"; name = "Observation Shutters"; opacity = 0},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/atmospherics/pipe/simple/supply/hidden,/turf/simulated/floor/plating,/area/medical/surgery) -"bOJ" = (/obj/structure/table,/obj/item/weapon/surgicaldrill,/turf/simulated/floor{icon_state = "white"},/area/medical/surgery) -"bOK" = (/obj/machinery/optable{id = "medbay"},/turf/simulated/floor{icon_state = "white"},/area/medical/surgery) +"bNG" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/obj/machinery/optable,/turf/simulated/floor{icon_state = "white"},/area/medical/surgery) +"bNH" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 10},/turf/simulated/floor{icon_state = "white"},/area/medical/surgery) +"bNI" = (/obj/structure/table,/obj/item/weapon/circular_saw,/turf/simulated/floor{icon_state = "white"},/area/medical/surgery) +"bNJ" = (/obj/machinery/r_n_d/server{id_with_download_string = "1"; id_with_upload_string = "1"; name = "Core R&D Server"; server_id = 1},/obj/machinery/atmospherics/pipe/simple,/turf/simulated/floor/grid{name = "Server Base"; nitrogen = 500; oxygen = 0; temperature = 80},/area/toxins/server) +"bNK" = (/turf/simulated/floor/grid{name = "Server Base"; nitrogen = 500; oxygen = 0; temperature = 80},/area/toxins/server) +"bNL" = (/obj/machinery/camera{c_tag = "Server Room"; dir = 2; network = "Research"},/turf/simulated/floor/grid{name = "Server Base"; nitrogen = 500; oxygen = 0; temperature = 80},/area/toxins/server) +"bNM" = (/obj/machinery/blackbox_recorder,/obj/machinery/atmospherics/pipe/simple,/turf/simulated/floor/grid{name = "Server Base"; nitrogen = 500; oxygen = 0; temperature = 80},/area/toxins/server) +"bNN" = (/obj/structure/disposalpipe/segment{dir = 1},/obj/item/device/radio/intercom{dir = 8; name = "Station Intercom (General)"; pixel_x = -28},/obj/machinery/atmospherics/pipe/manifold{color = "blue"; dir = 8; icon_state = "manifold-b-f"; level = 1; name = "pipe manifold"},/turf/simulated/floor{icon_state = "white"},/area/medical/research{name = "Research Division"}) +"bNO" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/obj/effect/sign/biohazard{pixel_x = 28},/turf/simulated/floor{icon_state = "white"},/area/medical/research{name = "Research Division"}) +"bNP" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 8; on = 1},/obj/machinery/requests_console{department = "Xenobiology"; departmentType = 0; pixel_x = -30; pixel_y = 0},/turf/simulated/floor{icon_state = "white"},/area/toxins/xenobiology) +"bNQ" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0; tag = "Streight"},/turf/simulated/floor{icon_state = "white"},/area/toxins/xenobiology) +"bNR" = (/obj/structure/stool/bed/chair,/turf/simulated/floor{icon_state = "white"},/area/toxins/xenobiology) +"bNS" = (/obj/machinery/atmospherics/valve,/turf/simulated/floor{icon_state = "white"},/area/toxins/xenobiology) +"bNT" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk,/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor{icon_state = "white"},/area/toxins/xenobiology) +"bNU" = (/obj/machinery/mass_driver{dir = 4; id = "toxinsdriver"},/turf/simulated/floor/plating,/area/toxins/observatory) +"bNV" = (/obj/machinery/light/small{dir = 1},/turf/simulated/floor/plating,/area/toxins/observatory) +"bNW" = (/turf/simulated/floor/plating,/area/toxins/observatory) +"bNX" = (/obj/machinery/door/poddoor{id = "toxinsdriver"; name = "Toxins Launcher Bay Door"},/turf/simulated/floor/plating,/area/toxins/observatory) +"bNY" = (/obj/machinery/door/poddoor{id = "toxinsdriver"; name = "Toxins Launcher Bay Door"},/turf/space,/area/toxins/test_area) +"bNZ" = (/obj/item/device/radio/beacon,/turf/simulated/floor/airless{icon_state = "bot"},/area/toxins/test_area) +"bOa" = (/obj/machinery/camera{c_tag = "East"; dir = 8; network = "Bomb Testing"; pixel_x = 0; pixel_y = -22},/obj/machinery/light/spot{dir = 4; layer = 2.8},/turf/simulated/floor/airless,/area/toxins/test_area) +"bOb" = (/obj/machinery/atmospherics/pipe/simple{dir = 4},/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 1},/turf/simulated/floor/plating,/area/maintenance/apmaint) +"bOc" = (/turf/simulated/wall,/area/assembly/chargebay) +"bOd" = (/obj/machinery/recharge_station,/obj/machinery/atmospherics/pipe/simple/supply/hidden,/turf/simulated/floor{icon_state = "bot"},/area/assembly/chargebay) +"bOe" = (/obj/machinery/recharge_station,/turf/simulated/floor{icon_state = "bot"},/area/assembly/chargebay) +"bOf" = (/obj/machinery/door/airlock/maintenance{name = "Assembly Line Maintenance"; req_access_txt = "12;29"},/turf/simulated/floor/plating,/area/maintenance/apmaint) +"bOg" = (/obj/effect/showcase{icon_state = "showcase_3"},/turf/simulated/floor{icon_state = "showroomfloor"},/area/assembly/chargebay) +"bOh" = (/obj/machinery/light,/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,/turf/simulated/floor/plating,/area/assembly/chargebay) +"bOi" = (/obj/machinery/atmospherics/portables_connector{dir = 4},/obj/structure/window/reinforced{dir = 1},/obj/machinery/portable_atmospherics/pump,/turf/simulated/floor{icon_state = "arrival"; dir = 8},/area/hallway/primary/aft) +"bOj" = (/obj/machinery/atmospherics/pipe/simple{color = "cyan"; dir = 10; icon_state = "intact-c"; initialize_directions = 10; level = 2},/turf/simulated/wall,/area/maintenance/asmaint) +"bOk" = (/obj/structure/closet/secure_closet/atmos_personal,/obj/machinery/light/small,/turf/simulated/floor,/area/atmos) +"bOl" = (/obj/structure/closet/wardrobe/atmospherics_yellow,/turf/simulated/floor,/area/atmos) +"bOm" = (/obj/machinery/vending/coffee,/turf/simulated/floor,/area/atmos) +"bOn" = (/obj/machinery/portable_atmospherics/canister/oxygen,/turf/simulated/floor{dir = 10; icon_state = "warning"},/area/atmos) +"bOo" = (/obj/machinery/portable_atmospherics/canister/carbon_dioxide,/turf/simulated/floor{icon_state = "warning"},/area/atmos) +"bOp" = (/obj/machinery/portable_atmospherics/canister/nitrogen,/turf/simulated/floor{icon_state = "warning"},/area/atmos) +"bOq" = (/obj/machinery/portable_atmospherics/canister/air,/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor{dir = 6; icon_state = "warning"},/area/atmos) +"bOr" = (/obj/machinery/light,/turf/simulated/floor,/area/atmos) +"bOs" = (/obj/machinery/atmospherics/binary/pump{dir = 1; icon_state = "intact_off"; name = "Emergency Tank Fill"; on = 0},/turf/simulated/floor,/area/atmos) +"bOt" = (/obj/machinery/atmospherics/pipe/simple{dir = 6; icon_state = "intact"; initialize_directions = 6; level = 2},/obj/machinery/meter,/turf/simulated/floor,/area/atmos) +"bOu" = (/obj/machinery/atmospherics/pipe/simple{color = "yellow"; icon_state = "intact-y"; level = 2},/obj/machinery/atmospherics/pipe/simple{dir = 4; icon_state = "intact"; level = 2},/turf/simulated/floor,/area/atmos) +"bOv" = (/obj/machinery/atmospherics/pipe/simple{color = "green"; icon_state = "intact-g"; level = 2},/obj/machinery/atmospherics/pipe/simple{dir = 4; icon_state = "intact"; level = 2},/turf/simulated/floor,/area/atmos) +"bOw" = (/obj/machinery/atmospherics/tvalve/digital{dir = 8; icon_state = "tvalve1"; state = 1; tag = "icon-tvalve0 (WEST)"},/turf/simulated/floor,/area/atmos) +"bOx" = (/obj/machinery/atmospherics/valve/digital{color = "yellow"; dir = 4; name = "Gas Mix Outlet Valve"},/turf/simulated/floor{icon_state = "green"; dir = 6},/area/atmos) +"bOy" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/atmospherics/pipe/simple{color = "yellow"; dir = 4; icon_state = "intact-y"; initialize_directions = 12; level = 2},/turf/simulated/floor/plating,/area/atmos) +"bOz" = (/obj/machinery/atmospherics/pipe/simple{color = "yellow"; dir = 4; icon_state = "intact-y"; initialize_directions = 12; level = 2},/obj/structure/grille,/turf/simulated/wall,/area) +"bOA" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 8; external_pressure_bound = 0; frequency = 1441; icon_state = "in"; id_tag = "waste_out"; initialize_directions = 1; internal_pressure_bound = 4000; on = 1; pressure_checks = 2; pump_direction = 0},/turf/simulated/floor/engine{name = "vacuum floor"; nitrogen = 0.01; oxygen = 0.01},/area/atmos) +"bOB" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden,/obj/machinery/light/small{dir = 4},/turf/simulated/wall,/area/medical/cmo) +"bOC" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -22},/turf/simulated/floor{dir = 8; icon_state = "barber"},/area/medical/cmo) +"bOD" = (/obj/structure/stool/bed/chair{dir = 1},/turf/simulated/floor{dir = 8; icon_state = "barber"},/area/medical/cmo) +"bOE" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/turf/simulated/floor/plating,/area/medical/cmo) +"bOF" = (/obj/machinery/atmospherics/unary/vent_pump{on = 1},/turf/simulated/floor{icon_state = "white"},/area/medical/medbay) +"bOG" = (/obj/machinery/door/firedoor/border_only,/obj/machinery/door/airlock/medical{name = "Surgery Observation"; req_access_txt = "5"},/turf/simulated/floor{icon_state = "dark"},/area/medical/surgery) +"bOH" = (/obj/machinery/hologram/holopad,/turf/simulated/floor{icon_state = "dark"},/area/medical/surgery) +"bOI" = (/obj/structure/stool/bed/chair{dir = 4},/turf/simulated/floor{icon_state = "dark"},/area/medical/surgery) +"bOJ" = (/obj/structure/grille,/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id = "Observation Shutters"; name = "Observation Shutters"; opacity = 0},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/atmospherics/pipe/simple/supply/hidden,/turf/simulated/floor/plating,/area/medical/surgery) +"bOK" = (/obj/structure/table,/obj/item/weapon/surgicaldrill,/turf/simulated/floor{icon_state = "white"},/area/medical/surgery) "bOL" = (/obj/machinery/atmospherics/unary/vent_scrubber{dir = 1; on = 1; scrub_N2O = 1; scrub_Toxins = 0},/turf/simulated/floor{icon_state = "white"},/area/medical/surgery) "bOM" = (/obj/structure/table,/obj/item/weapon/surgical_tool/bonegel,/obj/item/weapon/surgical_tool/bonesetter,/turf/simulated/floor{icon_state = "white"},/area/medical/surgery) "bON" = (/obj/machinery/atmospherics/unary/vent_pump{dir = 1; on = 1},/obj/machinery/light{icon_state = "tube1"; dir = 8},/turf/simulated/floor{icon_state = "dark"},/area/toxins/server) @@ -5368,7 +5368,7 @@ "bZl" = (/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plating/airless,/area) "bZm" = (/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plating,/area) "bZn" = (/obj/structure/disposalpipe/trunk{dir = 8},/obj/structure/disposaloutlet{dir = 4},/turf/simulated/floor/plating/airless,/area) -"bZo" = (/obj/machinery/computer/operating{id = "robotics"; name = "Robotics Operating Computer"},/turf/simulated/floor,/area/assembly/assembly_line) +"bZo" = (/obj/machinery/computer/operating,/turf/simulated/floor,/area/assembly/assembly_line) "bZp" = (/obj/structure/table,/obj/item/weapon/circular_saw,/obj/item/weapon/scalpel,/obj/structure/disposalpipe/segment{dir = 1; icon_state = "pipe-c"},/turf/simulated/floor,/area/assembly/assembly_line) "bZq" = (/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/wall,/area/assembly/assembly_line) "bZr" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"; tag = "90Curve"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"; tag = "90Curve"},/obj/machinery/atmospherics/pipe/simple/supply/hidden,/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/door/firedoor/border_only,/obj/machinery/door/airlock/maintenance{name = "Assembly Line Maintenance"; req_access_txt = "12;29"},/turf/simulated/floor/plating,/area/assembly/assembly_line) @@ -5414,7 +5414,7 @@ "caf" = (/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) "cag" = (/turf/simulated/wall/r_wall,/area/maintenance/portsolar) "cah" = (/turf/simulated/wall,/area/maintenance/portsolar) -"cai" = (/obj/machinery/optable{id = "robotics"; name = "Robotics Operating Table"},/turf/simulated/floor,/area/assembly/assembly_line) +"cai" = (/obj/machinery/optable,/turf/simulated/floor,/area/assembly/assembly_line) "caj" = (/obj/structure/table,/obj/item/device/mmi,/obj/item/device/mmi,/obj/item/device/mmi,/turf/simulated/floor,/area/assembly/assembly_line) "cak" = (/obj/structure/cable{tag = "Streight"; icon_state = "4-8"; pixel_x = 1; d1 = 4; d2 = 8},/turf/simulated/floor/plating,/area/maintenance/aft) "cal" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = "90Curve"},/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 5},/turf/simulated/floor/plating,/area/maintenance/aft) @@ -8775,16 +8775,16 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabJebATbJfbATbJgaaaaaeaaaaaabwSbwSbFfbJhbJhbJhbJhbFgbJiaaaaaaaaabthbJjbJkbJlbJmbJnbJobJpbJqbJqbJrbJsbJtbJubJqbJvbJvbJwbJxbJybJzbyMbJAbIjbJBbIkbJCbJDbIjbIjbJEbIjbIrbIsbIjbJFbJGbJHbIjbJIbJJbIzbJKbJLbJMaaaaaaaaaaaaaaaaaeaaaaaaaaaaaabwjbJNbJObJPbJQbJQbJQbJRbJQbJSbpnbJTbJUbJVbJWbJXbJYbJZbEAbKabKabKbbKcbKdbKebKfbKgbKhbKibKjbKkbKlbKmbKnbKobKjbKpbKqbKrbKqbHDbKsbKtbdLbHGbKubKvbKwbKxbKwbKyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarYaaaaaaaaeaaaaaabDCbDCbKzbFabFabFabFabKAbFabFabFabFabFabFabDCbDCaaeaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaeaaaaaaaaaaaeaaeaaeaaeaaaaaaaaabthbthbJkbKBbKCbIbbthbthbthbthbKDbKEbIdbKEbKFbKGbKHbKIbKJbtGbKKbwjbKLbIjbIjbKMbIjbIjbIjbIjbKNbKObKPbKQbKRbKSbKTbKUbKVbKWbKXbKYbKZbIBaaebLabLabLabLabLaaaeaaeaaeaaeaaebwjbwdbLbbLcbLdbLebLfbLgbLhbLibLjbBNbBNbBNbLkbLlbLmbBNbBNbBNbEAbLnbLobLpbLqbLrbKgbsWbLsbHDbLtbLubLvbKrbLwbHDbLxbLybLzbLAbHDbLBbLCbLDbLEbLFbLGbLHbKvbKwbLIaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabDCbFabFabFabFabFabFabLJbFabLKbFabFabFabFabFabDCbDCaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaeaaeaaaaaaaaaaaeaaeaaeaaaaaaaaaaaebthbJkbLLbLMbLNbLMbLMbLObthbLPbLQbLRbLQbLSbKGbLTbLUbLVbLWbLXbwjbLYbIjbIjbIkbLZbIjbIjbIjbIsbIjbIrbIjbKRbMabMbbMcbMdbJIbKWbMebMfbMgbMhbMibMjbMkbMkbLaaaeaaaaaaaaaaaebMlbwdbLbbLcbMmbMnbMobMobMpbMqbMrbBNbMsbMtbMubMvbFYbMwbMxbMybEAbMzbKgbMAbKgbMzbKgbsWbMBbMCbMDbMEbMFbMFbMFbMGbMFbISbMHbMIbHDbHDbMJbMKbHGbMLbHGbMMbMNbMObHGaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabDCbMPbMQbMRbMRbMRbMRbMSbFabMTbMRbLKbFabFabFabFabDCaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeachaaaaaaaaaaaeaaeaaeaaeaaeaaeaaebthbMUbMVbthbIbbthbthbMWbMXbLMbLMbMYbuAbuAbKGbMZbLUbtxbtGbtxbNabIjbIjbNbbNcbNdbNebNfbNgbNhbIjbIrbIjbKRbKSbNibNjbIjbJIbNkbNlbNmbIBaaebNnbNobMkbNpbLaaaeaaaaaaaaaaaebNqbwdbNrbNsbNtbNubNvbNwbNxbNybNzbNAbNBbNCbNDbNEbNFbNFbNGbNHbEAbNIbNJbLpbNKbNLbKgbNMbNNbKjbNObNPbKrbNQbKrbNPbKrbKrbNRbNRbNSbHDbMJbMKbHGbNTbNUbNVbNVbNVbNWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabNXbEYbEYbEYbEYbEYbEYbEYbNYbFbbFabFabFabFabNZbFbbDCaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaeaaeaaaaaaaaeaaeaaeaaeaaaaaaaaabOabJkbKBbObbOcbOdbthbthbthbthbthbthbOebthbKGbOfbOgbtxbtGbOhbOibOjbOkbOlbNcbOmbOnbOobOpbNhbIjbIrbIjbOqbOrbNibNjbOsbOtbOubOvbOwbOxbOybMibOzbMkbMkbLaaaeaaeaaeaaeaaebNqbwdbLbbOAbOBbOCbOCbMobODbxubOEbOFbOGbOHbOIbOJbFYbOKbOLbOMbEAbONbLpbOObLpbOPbKgbOQbORbHDbOSbOTbOUbOVbOWbOXbOYbOZbPabPbbPcbPdbPebMKbHGbHGbHGbHGbHGbHGbHGaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaaaaabDCbPfbPgbPhbJdbJdbJdbPibFabJcbJdbPjbFabFabFabFabDCaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaeaaaaaeaaeaaeaaaaaeaaaaaaaaabPkbJkbPlbObbPmbPnbPobPnbPpbPnbPobPnbPqbObbKGbKGbPrbPsbPtbPubPvbPwbHdbHdbIkbHdbHdbHdbHdbPxbIjbIrbPybPzbPAbPBbNjbPCbPDbNkbIjbIjbPEaaebLabLabLabLabLaaaeaaaaaaaaaaaebNqbwdbLbbPFbPGbPHbPIbPJbPKbPLbvibPMbPNbPObPPbPQbFVbFVbFWbPRbEAbPSbNJbPTbNJbPUbKgbPVbPWbHDbPXbPYbPZbQabQbbQcbQdbQabQebQbbPXbHDbQfbMKbccaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaebDCbFabFabFabFabFabFabLJbFabPjbFabFabFabFabFabDCbDCaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeachaaaaaaaaaaaeaaeaaeaaeaaeaaeaaebthbMUbMVbthbIbbthbthbMWbMXbLMbLMbMYbuAbuAbKGbMZbLUbtxbtGbtxbNabIjbIjbNbbNcbNdbNebNfbNgbNhbIjbIrbIjbKRbKSbNibNjbIjbJIbNkbNlbNmbIBaaebNnbNobMkbNpbLaaaeaaaaaaaaaaaebNqbwdbNrbNsbNtbNubNvbNwbNxbNybNzbNAbNBbNCbNDbNEbNFbNGbNHbNIbEAbNJbNKbLpbNLbNMbKgbNNbNObKjbNPbNQbKrbNRbKrbNQbKrbKrbNSbNSbNTbHDbMJbMKbHGbNUbNVbNWbNWbNWbNXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabNYbEYbEYbEYbEYbEYbEYbEYbNZbFbbFabFabFabFabOabFbbDCaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaeaaeaaaaaaaaeaaeaaeaaeaaaaaaaaabObbJkbKBbOcbOdbOebthbthbthbthbthbthbOfbthbKGbOgbOhbtxbtGbOibOjbOkbOlbOmbNcbOnbOobOpbOqbNhbIjbIrbIjbOrbOsbNibNjbOtbOubOvbOwbOxbOybOzbMibOAbMkbMkbLaaaeaaeaaeaaeaaebNqbwdbLbbOBbOCbODbODbMobOEbxubOFbOGbOHbOIbOJbOKbFYbFYbOLbOMbEAbONbLpbOObLpbOPbKgbOQbORbHDbOSbOTbOUbOVbOWbOXbOYbOZbPabPbbPcbPdbPebMKbHGbHGbHGbHGbHGbHGbHGaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaaaaabDCbPfbPgbPhbJdbJdbJdbPibFabJcbJdbPjbFabFabFabFabDCaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaeaaaaaeaaeaaeaaaaaeaaaaaaaaabPkbJkbPlbOcbPmbPnbPobPnbPpbPnbPobPnbPqbOcbKGbKGbPrbPsbPtbPubPvbPwbHdbHdbIkbHdbHdbHdbHdbPxbIjbIrbPybPzbPAbPBbNjbPCbPDbNkbIjbIjbPEaaebLabLabLabLabLaaaeaaaaaaaaaaaebNqbwdbLbbPFbPGbPHbPIbPJbPKbPLbvibPMbPNbPObPPbPQbFVbFVbFWbPRbEAbPSbNKbPTbNKbPUbKgbPVbPWbHDbPXbPYbPZbQabQbbQcbQdbQabQebQbbPXbHDbQfbMKbccaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaebDCbFabFabFabFabFabFabLJbFabPjbFabFabFabFabFabDCbDCaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaeaaeaaeaaeaaaaaabthbthbthbthbthbQgbQhbQibQjbQkbQlbQmbPqbQkbQlbQmbPqbQnbQobQpbQqbtxbtGbQrbQsbQtbQubQvbQwbQxbQybQzbQAbQBbQCbQDbQEbQFbQGbQHbQIbMdbJIbQJbKYbQKbQLbMhbMibQMbQNbQNbLaaaeaaaaaaaaaaaebNqbwdbLbbLcbQObQPbQQbQRbQSbxubQTbBNbQUbQVbQWbQXbFYbQYbQZbRabEAbRbbRbbRbbRbbKgbKgbPVbRcbHDbHDbHDbRdbRebRebRebRfbRebRebHDbHDbHDbMJbMKbccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaaaaaaaaaaeaaaaaaaaaaaeaaaaaabDCbDCbKzbFabFabFabFabRgbFabFabFabFabFabFabDCbDCaaeaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaeaaeaaeaaeaaeaaabOabRhbuAbRibRjbRkbRlbRmbRnbPqbPqbPqbPqbPqbPqbPqbPqbQnbQobtxbQqbtxbtGbRobRpbPwbIjbIjbRqbRrbKNbRsbRtbRubRvbRwbRwbRwbRwbRwbRxbIjbJIbNkbNlbRybRzaaebNnbRAbRBbRCbLaaaeaaeaaeaaeaaebFHbwdbLbbxhbJQbJQbJQbJQbJQbxubdsbBNbBNbBNbBNbBNbLmbRbbRbbRbbRbbRDbREbRFbRbbRGbRHbRIbRJbRKbRLbHDbRebRebRebRebRMbRebRebHDbRNbRObRPbMKbccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaebDCbDCbMTbMRbMRbFabFabFabFabFabFabFabFabDCbDCaaeaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaeaaeaaaaaaaaeaaabPkbuzbuAbRQbuAbJkbthbObbRRbPnbPnbPnbPqbPnbPnbPnbRSbObbObbObbRTbRUbtGbRVbRWbRXbRYbMebRZbSabSbbScbSdbSebNibSfbNbbNbbIjbSgbShbSibSjbSkbOvbSlbSmbSnbMibSobQNbQNbLaaaeaaaaaaaaaaaebwjbwdbLbbEebSpbSqbSrbSsbdsbxubdsbStbSubSvbSwbSxbFYbSybSzbSAbSBbSCbSDbSEbSFbSGbSHbSIbSJbSKbSLbHDbSMbSNbRebRebRebSNbSObHDbMJbMKbMKbMKbSPbccbccaaaaaeaaaaaaayoayoayoaaaaaaaaeaaaaaaaaeayoayoayoaaaaaaaaeaaaaaaaaeaaaaaaaaeaaaaaabDCbDCbGAbDCbDCbFabFabFabFabFabFabFabDCbDCaaeaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaeaaaaaaaaabSQbSQbSQbthbuAbSRbthbMUbthbOdbPqbQkbQlbSSbPqbQkbQlbQmbPqbPqbSTbPqbSUbtxbtGbSVbsqbsqbHdbSWbSXbSYbSZbTabHdbTbbNibTcbTdbIjbTebTfbTgbThbJIbNkbIjbTibRzaaebLabLabLabLabLaaaeaaaaaaaaaaaebwjbwdbLbbEebwjbdqbTjbqrbpnbTkbdsbTlbFYbFYbTmbFYbFYbTnbTobTpbTqbTrbTobTsbRbbTtbTtbTubTvbTtbTtbHDbRebRebRebTwbRebRebRebHDbTxbLDbLDbLDbTybTzbTybTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTBbTCbTDbTEbDCbDCbFabFabTFbFabFabDCbDCaaeaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaeaaaaaaaaaaaabSQbTGbTHbthbuAbRQbthbTIbTJbOdbPqbPqbTKbPqbTLbPqbTMbPqbPqbPqbTMbPqbSUbtxbtGbtxbxcbTNbsqbTObHdbLZbTPbTQbHdbTRbNibTcbTSbIjbIjbTTbTUbTVbJIbTWbKYbTXbQLbMhbMibTYbTZbUabLaaaeaaeaaeaaeaaebwjbwjbUbbUcbUdbjBbjBbjBbUebxubUfbStbUgbUhbUibUjbUhbSybUkbUlbRbbUmbTobUnbRbbUobUpbUpbUpbUpbUqbRbbHDbHDbHDbHDbHDbHDbHDbHDbQfbUrbUsbUtbccbccbccaaaaaeaaaaaaayoayoayoaaaaaaachaaaaaaaaeayoayoayoaaaaaaaaeaaaaaaaaeaaaaaaaaeaaeaaebUubUvbUwbUxbDCbDCbDCbFabFbbFabDCbDCaaeaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaeaaeaaeaaeaaeaaabObbRhbuAbRibRjbRkbRlbRmbRnbPqbPqbPqbPqbPqbPqbPqbPqbQnbQobtxbQqbtxbtGbRobRpbPwbIjbIjbRqbRrbKNbRsbRtbRubRvbRwbRwbRwbRwbRwbRxbIjbJIbNkbNlbRybRzaaebNnbRAbRBbRCbLaaaeaaeaaeaaeaaebFHbwdbLbbxhbJQbJQbJQbJQbJQbxubdsbBNbBNbBNbBNbBNbLmbRbbRbbRbbRbbRDbREbRFbRbbRGbRHbRIbRJbRKbRLbHDbRebRebRebRebRMbRebRebHDbRNbRObRPbMKbccaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaebDCbDCbMTbMRbMRbFabFabFabFabFabFabFabFabDCbDCaaeaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaeaaeaaaaaaaaeaaabPkbuzbuAbRQbuAbJkbthbOcbRRbPnbPnbPnbPqbPnbPnbPnbRSbOcbOcbOcbRTbRUbtGbRVbRWbRXbRYbMebRZbSabSbbScbSdbSebNibSfbNbbNbbIjbSgbShbSibSjbSkbOwbSlbSmbSnbMibSobQNbQNbLaaaeaaaaaaaaaaaebwjbwdbLbbEebSpbSqbSrbSsbdsbxubdsbStbSubSvbSwbSxbFYbSybSzbSAbSBbSCbSDbSEbSFbSGbSHbSIbSJbSKbSLbHDbSMbSNbRebRebRebSNbSObHDbMJbMKbMKbMKbSPbccbccaaaaaeaaaaaaayoayoayoaaaaaaaaeaaaaaaaaeayoayoayoaaaaaaaaeaaaaaaaaeaaaaaaaaeaaaaaabDCbDCbGAbDCbDCbFabFabFabFabFabFabFabDCbDCaaeaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaeaaaaaaaaabSQbSQbSQbthbuAbSRbthbMUbthbOebPqbQkbQlbSSbPqbQkbQlbQmbPqbPqbSTbPqbSUbtxbtGbSVbsqbsqbHdbSWbSXbSYbSZbTabHdbTbbNibTcbTdbIjbTebTfbTgbThbJIbNkbIjbTibRzaaebLabLabLabLabLaaaeaaaaaaaaaaaebwjbwdbLbbEebwjbdqbTjbqrbpnbTkbdsbTlbFYbFYbTmbFYbFYbTnbTobTpbTqbTrbTobTsbRbbTtbTtbTubTvbTtbTtbHDbRebRebRebTwbRebRebRebHDbTxbLDbLDbLDbTybTzbTybTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTAbTBbTCbTDbTEbDCbDCbFabFabTFbFabFabDCbDCaaeaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaeaaaaaaaaaaaabSQbTGbTHbthbuAbRQbthbTIbTJbOebPqbPqbTKbPqbTLbPqbTMbPqbPqbPqbTMbPqbSUbtxbtGbtxbxcbTNbsqbTObHdbLZbTPbTQbHdbTRbNibTcbTSbIjbIjbTTbTUbTVbJIbTWbKYbTXbQLbMhbMibTYbTZbUabLaaaeaaeaaeaaeaaebwjbwjbUbbUcbUdbjBbjBbjBbUebxubUfbStbUgbUhbUibUjbUhbSybUkbUlbRbbUmbTobUnbRbbUobUpbUpbUpbUpbUqbRbbHDbHDbHDbHDbHDbHDbHDbHDbQfbUrbUsbUtbccbccbccaaaaaeaaaaaaayoayoayoaaaaaaachaaaaaaaaeayoayoayoaaaaaaaaeaaaaaaaaeaaaaaaaaeaaeaaebUubUvbUwbUxbDCbDCbDCbFabFbbFabDCbDCaaeaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaeaaaaaaaaaaaaaaabSQbTGbUybUzbLMbUAbthbUBbUBbUCbUCbUCbUCbUCbUCbUCbUCbUDbUDbUCbUCbUCbUEbUFbUGbtxbUHbtxbtxbUIbUJbIjbTPbIjbUJbNjbNibUKbPzbNbbIjbIjbIjbIxbULbNkbNlbUMbRzaaebNnbUNbUObUPbLaaaeaaaaaaaaaaaeaaebwjbUQbURbUSbUTbUUbgLbgLbUVbUWbBNbBNbBNbBNbBNbBNbRbbRbbUXbUYbUZbVabVbbUpbVcbVdbVebVfbVebVgbRbbVhbVibVjbVkbVkbVkbVkbVkbRPbVlaaaaaaaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaeaaebVmbDAbDAbDBbDCbDCbDCbDCbDCbDCbDCaaeaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagaagaagaadaadaagaadaadaadajIaadaadaadaagaagaaaaaaaaeaaeaaaaaaaaaaaaaaaaaabSQbTGbVnbUCbUCbVobUCbVpbVqbUCbVrbVsbVtbUCbVubVvbVwbVxbVxbVybVzbVAbVBbtxbtGbVCbLVbVDbVEbVFbVGbHdbSXbVHbHdbVIbNibVJbVKbNbbIjbIjbIxbVLbVMbSkbOvbVNbSmbSnbMibVObTZbTZbLaaaeaaaaaaaaaaaaaaebwjbwjbwjbwjbwjbCObCPbCPbVPbAcbAcbAcbAcbAcbVQbAcbAcbAcbVRbVSbVTbTobVUbVVbVWbTobVXbVWbVYbTobRbbpEbVZbUrbWabccbccbccbccbccbccaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaeaaeaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagaagaagaadaadaagaadaadaadajIaadaadaadaagaagaaaaaaaaeaaeaaaaaaaaaaaaaaaaaabSQbTGbVnbUCbUCbVobUCbVpbVqbUCbVrbVsbVtbUCbVubVvbVwbVxbVxbVybVzbVAbVBbtxbtGbVCbLVbVDbVEbVFbVGbHdbSXbVHbHdbVIbNibVJbVKbNbbIjbIjbIxbVLbVMbSkbOwbVNbSmbSnbMibVObTZbTZbLaaaeaaaaaaaaaaaaaaebwjbwjbwjbwjbwjbCObCPbCPbVPbAcbAcbAcbAcbAcbVQbAcbAcbAcbVRbVSbVTbTobVUbVVbVWbTobVXbVWbVYbTobRbbpEbVZbUrbWabccbccbccbccbccbccaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaeaaeaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagaaaaaaaaeaaeaaaaaeaaeaaaaaaaaeaaeaaeaaaaagaaaaaeaaeaaaaaaaaaaaaaaaaaaaaabSQbTGbVnbWbbWcbVxbWdbWebVxbWfbWgbWhbVxbWibVxbWhbVxbVxbVxbWjbWkbtxbWlbWmbtGbWnbWobsqbsqbsqbsqbWpbWqbWrbHdbWsbNibIxbWtbIybWubIybWvbWwbKWbWxbIjbIjbRzaaebLabLabLabLabLaaaeaaaaaaaaaaaaaaaaaeaaeaaaaaebwjbwjbwjbwdbwdbwdbWybWzbWzbWzbWAbWzbWzbWzbpEbVSbWBbTobWCbWDbVWbWEbWFbWGbWHbWIbRbbpEbVZbrYaaaaaaaaaaaaaaeaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagaaabWJbWKbWLaaabWJbWKbWLaaabWJbWKbWLaaebWMaaeaaeaaaaaaaaaaaaaaaaaaaaaaaabSQbTGbVnbWNbWObVxbWgbWebVxbWPbWQbWQbWQbWQbWQbWQbWRbWQbWSbWjbWTbtxbQqbtxbtGbWUbWVbWWbWXbWYbWZbXabXbbXcbHdbXdbXebXfbXgbXgbXfbXgbXhbXibJIbXjbKYbXkbQLbMhbMibXlbXmbXmbLaaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaaebwjbXnbXobFCbFBbWzbXpbXqbXrbXsbXtbWzbpEbVSbXubXvbXwbXxbXybXzbXAbXBbXCbXDbRbbpEbXEbrYaaaaaaaaeaaeaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagaaabWJbXFbWLaaabWJbXFbWLaaabWJbXFbWLaaeaaeaaeaaeaaaaaaaaaaaaaaaaaaaaaaaabSQbTGbVnbUCbUCbXGbVxbWebXHbXIbXIbXJbXKbVxbVxbXLbVxbVxbXMbXNbXObtxbXPbtxbtGbVCbsrbXQbXRbXSbXTbXUbXVbXWbHdbNjbIjbKWbXgbXgbXXbXYbXZbXebYabYbbYcbYdbRzaaebNnbYebYfbYgbLaaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaebWzbWzbWzbWzbWzbWzbYhbYhbXrbYhbYibWzbqIbYjbYkbTobXwbTobYlbTobTobTobTobYmbRbbpEbVZbrYaaaaaaaaaaaeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa