diff --git a/code/__DEFINES/pda.dm b/code/__DEFINES/pda.dm new file mode 100644 index 00000000000..d22b90870b0 --- /dev/null +++ b/code/__DEFINES/pda.dm @@ -0,0 +1,3 @@ +#define PDA_APP_UPDATE 0 +#define PDA_APP_NOUPDATE 1 +#define PDA_APP_UPDATE_SLOW 2 \ No newline at end of file diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index b82cd7ab9d1..5c13314833c 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -319,17 +319,9 @@ LE.current = T LE.yo = U.y - T.y LE.xo = U.x - T.x - spawn( 1 ) + spawn(1) LE.process() -/mob/living/carbon/human/LaserEyes() - if(nutrition>0) - ..() - nutrition = max(nutrition - rand(1,5),0) - handle_regular_hud_updates() - else - src << "\red You're out of energy! You need food!" - /mob/proc/PowerGlove(atom/A) return diff --git a/code/_onclick/hud/ai.dm b/code/_onclick/hud/ai.dm index 790cbd305bc..0049537e9b4 100644 --- a/code/_onclick/hud/ai.dm +++ b/code/_onclick/hud/ai.dm @@ -100,7 +100,7 @@ /obj/screen/ai/pda_msg_send/Click() if(isAI(usr)) var/mob/living/silicon/ai/AI = usr - AI.cmd_send_pdamesg(usr) + AI.aiPDA.cmd_send_pdamesg() /obj/screen/ai/pda_msg_show name = "PDA - Show Message Log" @@ -109,7 +109,7 @@ /obj/screen/ai/pda_msg_show/Click() if(isAI(usr)) var/mob/living/silicon/ai/AI = usr - AI.cmd_show_message_log(usr) + AI.aiPDA.cmd_show_message_log() /obj/screen/ai/image_take name = "Take Image" diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm index 16d00449a55..e168b36db2f 100644 --- a/code/datums/uplink_item.dm +++ b/code/datums/uplink_item.dm @@ -365,11 +365,12 @@ var/list/uplink_items = list() surplus = 0 /datum/uplink_item/dangerous/emp - name = "EMP Kit" - desc = "A box that contains two EMP grenades, an EMP implant and a short ranged recharging device disguised as a flashlight. Useful to disrupt communication and silicon lifeforms." - reference = "EMP" + name = "EMP Grenades and Implanter Kit" + desc = "A box that contains two EMP grenades and an EMP implant. Useful to disrupt communication, \ + security's energy weapons, and silicon lifeforms when you're in a tight spot." + reference = "EMPK" item = /obj/item/weapon/storage/box/syndie_kit/emp - cost = 5 + cost = 2 /datum/uplink_item/dangerous/syndicate_minibomb name = "Syndicate Minibomb" @@ -658,6 +659,15 @@ var/list/uplink_items = list() cost = 2 surplus = 30 +/datum/uplink_item/stealthy_tools/emplight + name = "EMP Flashlight" + desc = "A small, self-charging, short-ranged EMP device disguised as a flashlight. \ + Useful for disrupting headsets, cameras, and borgs during stealth operations." + reference = "EMPL" + item = /obj/item/device/flashlight/emp + cost = 2 + surplus = 30 + // DEVICE AND TOOLS /datum/uplink_item/device_tools diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 08e8f74b312..73ce77d0474 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -133,11 +133,11 @@ else msg += "However, we were unable to send you the $[pay] you're entitled." if(useMS && P) - // THIS SHOULD HAVE DONE EVERYTHING FOR ME useMS.send_pda_message("[P.owner]", "[command_name()] Payroll", msg) - // BUT NOPE, NEED TO DO THIS BULLSHIT. - P.play_ringtone() + var/datum/data/pda/app/messenger/PM = P.find_program(/datum/data/pda/app/messenger) + if(PM) + PM.play_ringtone() //Search for holder of the PDA. var/mob/living/L = null if(P.loc && isliving(P.loc)) diff --git a/code/game/gamemodes/miniantags/borer/borer.dm b/code/game/gamemodes/miniantags/borer/borer.dm index a1ee69ac9b7..83d6cf04063 100644 --- a/code/game/gamemodes/miniantags/borer/borer.dm +++ b/code/game/gamemodes/miniantags/borer/borer.dm @@ -60,13 +60,92 @@ pass_flags = PASSTABLE ventcrawler = 2 + var/talk_inside_host = 0 // So that borers don't accidentally give themselves away on a botched message var/used_dominate - var/chemicals = 10 // Chemicals used for reproduction and spitting neurotoxin. + var/chemicals = 10 // Chemicals used for reproduction and chemical injection. + var/max_chems = 250 // How many chemicals that can be stored in total var/mob/living/carbon/human/host // Human host for the brain worm. var/truename // Name used for brainworm-speak. var/mob/living/captive_brain/host_brain // Used for swapping control of the body back and forth. var/controlling // Used in human death check. var/docile = 0 // Sugar can stop borers from acting. + var/list/borer_injection_chems = list("mannitol","salglu_solution","methamphetamine", "hydrocodone", "spaceacillin", "mitocholide", "charcoal", "salbutamol", "capulettium_plus") + +/mob/living/simple_animal/borer/verb/Communicate() + set category = "Borer" + set name = "Converse with Host" + set desc = "Send a silent message to your host." + if(!host) + src << "You do not have a host to communicate with!" + return + + var/input = stripped_input(src, "Please enter a message to tell your host.", "Borer", "") + if(!input) return + + + var/say_string = (docile) ? "slurs" :"states" + if(host) + host << "[src.truename] [say_string]: [input]" + log_say("Borer Communication: [key_name(src)] -> [key_name(host)] : [input]") + for(var/M in dead_mob_list) + if(istype(M, /mob/dead/observer)) + M << "Borer Communication from [src.truename] ([ghost_follow_link(src, ghost=M)]): [input]" + src << "[src.truename] [say_string]: [input]" + host.verbs += /mob/living/proc/borer_comm + +/mob/living/simple_animal/borer/verb/toggle_silence_inside_host() + set name = "Toggle speech inside Host" + set category = "Borer" + set desc = "Toggle whether you will be able to say audible messages while inside your host." + + if(talk_inside_host) + talk_inside_host = 0 + src << "You will no longer talk audibly while inside a host." + else + talk_inside_host = 1 + src << "You will now be able to audibly speak from inside of a host." + +/mob/living/proc/borer_comm() + set name = "Converse with Borer" + set category = "Borer" + set desc = "Communicate mentally with your borer." + + + var/mob/living/simple_animal/borer/B = src.has_brain_worms() + if(!B) + return + + var/input = stripped_input(src, "Please enter a message to tell the borer.", "Message", "") + if(!input) return + + B << "[src] says: [input]" + log_say("Borer Communication: [key_name(src)] -> [key_name(B)] : [input]") + + for(var/M in dead_mob_list) + if(istype(M, /mob/dead/observer)) + M << "Borer Communication from [src] ([ghost_follow_link(src, ghost=M)]): [input]" + src << "[src] says: [input]" + +/mob/living/proc/trapped_mind_comm() + set name = "Converse with Trapped Mind" + set category = "Borer" + set desc = "Communicate mentally with the trapped mind of your host." + + + var/mob/living/simple_animal/borer/B = src.has_brain_worms() + if(!B || !B.host_brain) + return + var/mob/living/captive_brain/CB = B.host_brain + var/input = stripped_input(src, "Please enter a message to tell the trapped mind.", "Message", "") + if(!input) return + + CB << "[B.truename] says: [input]" + log_say("Borer Communication: [key_name(B)] -> [key_name(CB)] : [input]") + + for(var/M in dead_mob_list) + if(istype(M, /mob/dead/observer)) + M << "Borer Communication from [B] ([ghost_follow_link(src, ghost=M)]): [input]" + src << "[B.truename] says: [input]" /mob/living/simple_animal/borer/Life() @@ -91,7 +170,7 @@ src << "\blue You shake off your lethargy as the sugar leaves your host's blood." docile = 0 - if(chemicals < 250) + if(chemicals < max_chems) chemicals++ if(controlling) @@ -109,11 +188,16 @@ /mob/living/simple_animal/borer/New(var/by_gamemode=0) ..() add_language("Cortical Link") - truename = "[pick("Primary","Secondary","Tertiary","Quaternary")] [rand(1000,9999)]" + updatename() if(!by_gamemode) request_player() +/mob/living/simple_animal/borer/proc/updatename() + var/index_num = rand(1000,9999) + real_name = "Cortical Borer ([index_num])" + truename = "[pick("Primary","Secondary","Tertiary","Quaternary")] [index_num]" + /mob/living/simple_animal/borer/Stat() ..() statpanel("Status") @@ -134,7 +218,7 @@ M << "Cortical link, [truename]: [copytext(message, 2)]" /mob/living/simple_animal/borer/verb/dominate_victim() - set category = "Alien" + set category = "Borer" set name = "Dominate Victim" set desc = "Freeze the limbs of a potential host with supernatural fear." @@ -174,7 +258,7 @@ used_dominate = world.time /mob/living/simple_animal/borer/verb/bond_brain() - set category = "Alien" + set category = "Borer" set name = "Assume Control" set desc = "Fully connect to the brain of your host." @@ -240,13 +324,15 @@ host.verbs += /mob/living/carbon/proc/release_control host.verbs += /mob/living/carbon/proc/punish_host host.verbs += /mob/living/carbon/proc/spawn_larvae + host.verbs -= /mob/living/proc/borer_comm + host.verbs += /mob/living/proc/trapped_mind_comm if(src && !src.key) src.key = "@[borer_key]" return /mob/living/simple_animal/borer/verb/secrete_chemicals() - set category = "Alien" + set category = "Borer" set name = "Secrete Chemicals (30)" set desc = "Push some chemicals into your host's bloodstream." @@ -266,8 +352,12 @@ if(chemicals < chem_cost) src << "You don't have enough chemicals!" - - var/chem = input("Select a chemical to secrete.", "Chemicals") as null|anything in list("mannitol","salglu_solution","methamphetamine", "hydrocodone", "spaceacillin", "mitocholide", "charcoal", "salbutamol", "capulettium_plus") + var/list/nice_name_chem_list = list() + for(var/rgnt in borer_injection_chems) + var/datum/reagent/R2 = chemical_reagents_list[rgnt] + nice_name_chem_list[R2.name] = rgnt + var/chem_name = input("Select a chemical to secrete.", "Chemicals") as null|anything in nice_name_chem_list + var/chem = nice_name_chem_list[chem_name] if(!chem || chemicals < chem_cost || !host || controlling || !src || stat) //Sanity check. return @@ -278,12 +368,12 @@ src << "Doing so would cause grievous harm to your host, reducing ability to reproduce. Aborting." return - src << "You squirt a measure of [chem] from your reservoirs into [host]'s bloodstream." + src << "You squirt a measure of [chem_name] from your reservoirs into [host]'s bloodstream." host.reagents.add_reagent(chem, injection_amount) chemicals -= chem_cost /mob/living/simple_animal/borer/verb/release_host() - set category = "Alien" + set category = "Borer" set name = "Release Host" set desc = "Slither out of your host." @@ -332,6 +422,8 @@ host.verbs -= /mob/living/carbon/proc/release_control host.verbs -= /mob/living/carbon/proc/punish_host host.verbs -= /mob/living/carbon/proc/spawn_larvae + host.verbs += /mob/living/proc/borer_comm + host.verbs -= /mob/living/proc/trapped_mind_comm if(host_brain) @@ -369,6 +461,71 @@ return + +//Brain slug proc for voluntary removal of control. +/mob/living/carbon/proc/release_control() + + set category = "Borer" + set name = "Release Control" + set desc = "Release control of your host's body." + + var/mob/living/simple_animal/borer/B = has_brain_worms() + + if(B && B.host_brain) + src << "\red You withdraw your probosci, releasing control of [B.host_brain]" + + B.detatch() + + else + src << "\red ERROR NO BORER OR BRAINMOB DETECTED IN THIS MOB, THIS IS A BUG !" + +//Brain slug proc for tormenting the host. +/mob/living/carbon/proc/punish_host() + set category = "Borer" + set name = "Torment host" + set desc = "Punish your host with agony." + + var/mob/living/simple_animal/borer/B = has_brain_worms() + + if(!B) + return + + if(B.host_brain.ckey) + src << "\red You send a punishing spike of psychic agony lancing into your host's brain." + B.host_brain << "\red Horrific, burning agony lances through you, ripping a soundless scream from your trapped mind!" + +//Check for brain worms in head. +/mob/proc/has_brain_worms() + + for(var/I in contents) + if(istype(I,/mob/living/simple_animal/borer)) + return I + + return 0 + +/mob/living/carbon/proc/spawn_larvae() + set category = "Borer" + set name = "Reproduce (100)" + set desc = "Spawn several young." + + var/mob/living/simple_animal/borer/B = has_brain_worms() + + if(!B) + return + + if(B.chemicals >= 100) + src << "\red Your host twitches and quivers as you rapdly excrete several larvae from your sluglike body." + visible_message("\red [src] heaves violently, expelling a rush of vomit and a wriggling, sluglike creature!") + B.chemicals -= 100 + + new /obj/effect/decal/cleanable/vomit(get_turf(src)) + playsound(loc, 'sound/effects/splat.ogg', 50, 1) + new /mob/living/simple_animal/borer(get_turf(src)) + + else + src << "You do not have enough chemicals stored to reproduce." + return + /mob/living/simple_animal/borer/proc/leave_host() if(!host) return @@ -382,12 +539,13 @@ host.machine = null var/mob/living/H = host + H.verbs -= /mob/living/proc/borer_comm H.status_flags &= ~PASSEMOTES host = null return /mob/living/simple_animal/borer/verb/infest() - set category = "Alien" + set category = "Borer" set name = "Infest" set desc = "Infest a suitable humanoid host." @@ -435,18 +593,12 @@ if(M in view(1, src)) src << "You wiggle into [M]'s ear." + /* if(!M.stat) M << "Something disgusting and slimy wiggles into your ear!" + */ // Let's see how stealthborers work out - src.host = M - src.forceMove(M) - - if(istype(M,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - var/obj/item/organ/external/head = H.get_organ("head") - head.implants += src - - host.status_flags |= PASSEMOTES + perform_infestation(M) return else @@ -462,8 +614,6 @@ var/obj/item/organ/external/head = H.get_organ("head") head.implants += src - host_brain.name = M.name - host_brain.real_name = M.real_name host.status_flags |= PASSEMOTES /mob/living/simple_animal/borer/can_use_vents() @@ -494,13 +644,12 @@ if(!candidate) return - src.mind = candidate.mob.mind - src.ckey = candidate.ckey + src.key = candidate.key if(src.mind) src.mind.assigned_role = "Cortical Borer" /mob/living/simple_animal/borer/verb/borerhide() - set category = "Alien" + set category = "Borer" set name = "Hide" set desc = "Allows to hide beneath tables or certain items. Toggled on or off." @@ -509,13 +658,16 @@ if (layer != TURF_LAYER+0.2) layer = TURF_LAYER+0.2 - src << text("\green You are now hiding.") - for(var/mob/O in oviewers(src, null)) - if ((O.client && !( O.blinded ))) - O << text("[] scurries to the ground!", src) + src << "\green You are now hiding." else layer = MOB_LAYER - src << text("\green You have stopped hiding.") - for(var/mob/O in oviewers(src, null)) - if ((O.client && !( O.blinded ))) - O << text("[] slowly peaks up from the ground...", src) + src << "\green You have stopped hiding." + +/mob/living/simple_animal/borer/say(var/message) + var/datum/language/dialect = parse_language(message) + if(!dialect) + dialect = get_default_language() + if(!istype(dialect, /datum/language/corticalborer) && loc == host && !talk_inside_host) + src << "You've disabled audible speech while inside a host! Re-enable it under the borer tab, or stick to borer communications." + return + ..() diff --git a/code/game/gamemodes/mutiny/mutiny.dm b/code/game/gamemodes/mutiny/mutiny.dm index 1d2faebe5ff..113cffa46c0 100644 --- a/code/game/gamemodes/mutiny/mutiny.dm +++ b/code/game/gamemodes/mutiny/mutiny.dm @@ -105,7 +105,9 @@ datum/game_mode/mutiny if (!pda) return 0 - pda.play_ringtone() + var/datum/data/pda/app/messenger/pdam = pda.find_program(/datum/data/pda/app/messenger) + if(pdam) + pdam.play_ringtone() head_mutineer.current << fluff.get_pda_body() return 1 diff --git a/code/game/gamemodes/shadowling/shadowling_abilities.dm b/code/game/gamemodes/shadowling/shadowling_abilities.dm index f4186557627..2dfa31cc4a0 100644 --- a/code/game/gamemodes/shadowling/shadowling_abilities.dm +++ b/code/game/gamemodes/shadowling/shadowling_abilities.dm @@ -80,8 +80,9 @@ F.update_brightness() else if(istype(I, /obj/item/device/pda)) var/obj/item/device/pda/P = I - P.fon = 0 - P.set_light(0) + var/datum/data/pda/utility/flashlight/FL = P.find_program(/datum/data/pda/utility/flashlight) + if(FL && FL.fon) + FL.start() else if(istype(I, /obj/item/clothing/head/helmet/space/rig)) var/obj/item/clothing/head/helmet/space/rig/R = I if(R.on) diff --git a/code/game/machinery/bots/ed209bot.dm b/code/game/machinery/bots/ed209bot.dm index bb6ca81b8e6..99ff5796acc 100644 --- a/code/game/machinery/bots/ed209bot.dm +++ b/code/game/machinery/bots/ed209bot.dm @@ -38,16 +38,6 @@ bot_type_name = "ED-209" bot_filter = RADIO_SECBOT - //List of weapons that secbots will not arrest for - var/safe_weapons = list(\ - /obj/item/weapon/gun/energy/laser/bluetag,\ - /obj/item/weapon/gun/energy/laser/redtag,\ - /obj/item/weapon/gun/energy/laser/practice,\ - /obj/item/weapon/melee/classic_baton/telescopic,\ - /obj/item/weapon/gun/energy/kinetic_accelerator,\ - /obj/item/weapon/gun/energy/floragun) - - /obj/item/weapon/ed209_assembly name = "\improper ED-209 assembly" desc = "Some sort of bizarre assembly." @@ -395,9 +385,8 @@ Auto Patrol[]"}, continue /obj/machinery/bot/ed209/proc/check_for_weapons(var/obj/item/slot_item) - if(istype(slot_item, /obj/item/weapon/gun) || istype(slot_item, /obj/item/weapon/melee)) - if(!(slot_item.type in safe_weapons)) - return 1 + if(slot_item && slot_item.needs_permit) + return 1 return 0 /obj/machinery/bot/ed209/explode() diff --git a/code/game/machinery/bots/secbot.dm b/code/game/machinery/bots/secbot.dm index 8e34b0ae19e..729ce464b8c 100644 --- a/code/game/machinery/bots/secbot.dm +++ b/code/game/machinery/bots/secbot.dm @@ -31,16 +31,6 @@ bot_type_name = "Secbot" bot_filter = RADIO_SECBOT - //List of weapons that secbots will not arrest for - var/safe_weapons = list(\ - /obj/item/weapon/gun/energy/laser/bluetag,\ - /obj/item/weapon/gun/energy/laser/redtag,\ - /obj/item/weapon/gun/energy/laser/practice,\ - /obj/item/weapon/melee/classic_baton/telescopic,\ - /obj/item/weapon/gun/energy/kinetic_accelerator,\ - /obj/item/weapon/gun/energy/floragun) - - /obj/machinery/bot/secbot/beepsky name = "Officer Beepsky" desc = "It's Officer Beepsky! Powered by a potato and a shot of whiskey." @@ -378,9 +368,8 @@ Auto Patrol: []"}, else continue /obj/machinery/bot/secbot/proc/check_for_weapons(var/obj/item/slot_item) - if(istype(slot_item, /obj/item/weapon/gun) || istype(slot_item, /obj/item/weapon/melee)) - if(!(slot_item.type in safe_weapons)) - return 1 + if(slot_item && slot_item.needs_permit) + return 1 return 0 /obj/machinery/bot/secbot/explode() diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index 5b1e1610e83..6e9c41ff983 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -205,8 +205,10 @@ info = X.info else P = W - itemname = P.name - info = P.notehtml + var/datum/data/pda/app/notekeeper/N = P.find_program(/datum/data/pda/app/notekeeper) + if(N) + itemname = P.name + info = N.notehtml U << "You hold \the [itemname] up to the camera ..." U.changeNext_move(CLICK_CD_MELEE) for(var/mob/O in player_list) diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm index b2af98e1b5a..7277bc6a366 100644 --- a/code/game/machinery/computer/arcade.dm +++ b/code/game/machinery/computer/arcade.dm @@ -6,41 +6,7 @@ icon_keyboard = null icon_screen = "invaders" light_color = "#00FF00" - - var/list/prizes = list( /obj/item/weapon/storage/box/snappops = 2, - /obj/item/toy/AI = 2, - /obj/item/clothing/under/syndicate/tacticool = 2, - /obj/item/toy/blink = 2, - /obj/item/weapon/storage/box/fakesyndiesuit = 2, - /obj/item/toy/sword = 2, - /obj/item/weapon/gun/projectile/revolver/capgun = 2, - /obj/item/toy/crossbow = 2, - /obj/item/weapon/storage/fancy/crayons = 2, - /obj/item/toy/spinningtoy = 2, - /obj/item/toy/crossbow/tommygun = 2, - /obj/random/prize = 5, - /obj/item/toy/nuke = 2, - /obj/item/toy/cards/deck = 2, - /obj/random/carp_plushie = 2, - /obj/item/toy/minimeteor = 2, - /obj/item/toy/redbutton = 2, - /obj/item/toy/owl = 2, - /obj/item/toy/griffin = 2, - /obj/item/clothing/head/blob = 2, - /obj/item/weapon/id_decal/gold = 2, - /obj/item/weapon/id_decal/silver = 2, - /obj/item/weapon/id_decal/prisoner = 2, - /obj/item/weapon/id_decal/centcom = 2, - /obj/item/weapon/id_decal/emag = 2, - /obj/item/weapon/spellbook/oneuse/fake_gib = 2, - /obj/item/toy/foamblade = 2, - /obj/item/toy/flash = 2, - /obj/item/toy/minigibber = 2, - /obj/item/toy/toy_xeno = 2, - /obj/random/figure = 16, - /obj/random/plushie = 7, - /obj/item/stack/tile/fakespace/loaded = 2, - ) + var/prize = /obj/item/stack/tickets /obj/machinery/computer/arcade/power_change() ..() @@ -56,28 +22,22 @@ qdel(src) -/obj/machinery/computer/arcade/proc/prizevend() +/obj/machinery/computer/arcade/proc/prizevend(var/score) if(!contents.len) - var/prizeselect = pickweight(prizes) - new prizeselect(src.loc) - - if(istype(prizeselect, /obj/item/weapon/gun/projectile/revolver/capgun)) //Ammo comes with the gun - new /obj/item/ammo_box/caps(src.loc) - - else if(istype(prizeselect, /obj/item/clothing/suit/syndicatefake)) //Helmet is part of the suit - new /obj/item/clothing/head/syndicatefake(src.loc) - + var/prize_amount + if(score) + prize_amount = score + else + prize_amount = rand(1, 10) + new prize(get_turf(src), prize_amount) else var/atom/movable/prize = pick(contents) - prize.loc = src.loc + prize.loc = get_turf(src) /obj/machinery/computer/arcade/emp_act(severity) ..(severity) - if(stat & (NOPOWER|BROKEN)) return - - var/empprize = null var/num_of_prizes = 0 switch(severity) if(1) @@ -85,9 +45,8 @@ if(2) num_of_prizes = rand(0,2) for(var/i = num_of_prizes; i > 0; i--) - empprize = pickweight(prizes) - new empprize(src.loc) - explosion(src.loc, -1, 0, 1+num_of_prizes, flame_range = 1+num_of_prizes) + prizevend() + explosion(get_turf(src), -1, 0, 1+num_of_prizes, flame_range = 1+num_of_prizes) /obj/machinery/computer/arcade/battle @@ -116,20 +75,20 @@ name_part1 = pick("the Automatic ", "Farmer ", "Lord ", "Professor ", "the Cuban ", "the Evil ", "the Dread King ", "the Space ", "Lord ", "the Great ", "Duke ", "General ") name_part2 = pick("Melonoid", "Murdertron", "Sorcerer", "Ruin", "Jeff", "Ectoplasm", "Crushulon", "Uhangoid", "Vhakoid", "Peteoid", "slime", "Griefer", "ERPer", "Lizard Man", "Unicorn", "Bloopers") - src.enemy_name = replacetext((name_part1 + name_part2), "the ", "") - src.name = (name_action + name_part1 + name_part2) + enemy_name = replacetext((name_part1 + name_part2), "the ", "") + name = (name_action + name_part1 + name_part2) /obj/machinery/computer/arcade/battle/attack_hand(mob/user as mob) if(..()) return user.set_machine(src) var/dat = "Close" - dat += "

[src.enemy_name]

" + dat += "

[enemy_name]

" - dat += "

[src.temp]

" - dat += "
Health: [src.player_hp] | Magic: [src.player_mp] | Enemy Health: [src.enemy_hp]
" + dat += "

[temp]

" + dat += "
Health: [player_hp] | Magic: [player_mp] | Enemy Health: [enemy_hp]
" - if (src.gameover) + if (gameover) dat += "
New Game" else dat += "
Attack | " @@ -142,7 +101,7 @@ //onclose(user, "arcade") var/datum/browser/popup = new(user, "arcade", "Space Villian 2000") popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) + popup.set_title_image(user.browse_rsc_icon(icon, icon_state)) popup.open() return @@ -150,48 +109,48 @@ if(..()) return - if (!src.blocked && !src.gameover) + if (!blocked && !gameover) if (href_list["attack"]) - src.blocked = 1 + blocked = 1 var/attackamt = rand(2,6) - src.temp = "You attack for [attackamt] damage!" + temp = "You attack for [attackamt] damage!" playsound(src.loc, 'sound/arcade/Hit.ogg', 20, 1, extrarange = -6, falloff = 10) - src.updateUsrDialog() + updateUsrDialog() if(turtle > 0) turtle-- sleep(10) - src.enemy_hp -= attackamt - src.arcade_action() + enemy_hp -= attackamt + arcade_action() else if (href_list["heal"]) - src.blocked = 1 + blocked = 1 var/pointamt = rand(1,3) var/healamt = rand(6,8) - src.temp = "You use [pointamt] magic to heal for [healamt] damage!" + temp = "You use [pointamt] magic to heal for [healamt] damage!" playsound(src.loc, 'sound/arcade/Heal.ogg', 20, 1, extrarange = -6, falloff = 10) - src.updateUsrDialog() + updateUsrDialog() turtle++ sleep(10) - src.player_mp -= pointamt - src.player_hp += healamt - src.blocked = 1 - src.updateUsrDialog() - src.arcade_action() + player_mp -= pointamt + player_hp += healamt + blocked = 1 + updateUsrDialog() + arcade_action() else if (href_list["charge"]) - src.blocked = 1 + blocked = 1 var/chargeamt = rand(4,7) - src.temp = "You regain [chargeamt] points" + temp = "You regain [chargeamt] points" playsound(src.loc, 'sound/arcade/Mana.ogg', 20, 1, extrarange = -6, falloff = 10) - src.player_mp += chargeamt + player_mp += chargeamt if(turtle > 0) turtle-- - src.updateUsrDialog() + updateUsrDialog() sleep(10) - src.arcade_action() + arcade_action() if (href_list["close"]) usr.unset_machine() @@ -207,49 +166,50 @@ turtle = 0 if(emagged) - src.New() + New() emagged = 0 - src.add_fingerprint(usr) - src.updateUsrDialog() + add_fingerprint(usr) + updateUsrDialog() return /obj/machinery/computer/arcade/battle/proc/arcade_action() - if ((src.enemy_mp <= 0) || (src.enemy_hp <= 0)) + if ((enemy_mp <= 0) || (enemy_hp <= 0)) if(!gameover) - src.gameover = 1 - src.temp = "[src.enemy_name] has fallen! Rejoice!" + gameover = 1 + temp = "[enemy_name] has fallen! Rejoice!" playsound(src.loc, 'sound/arcade/Win.ogg', 20, 1, extrarange = -6, falloff = 10) if(emagged) feedback_inc("arcade_win_emagged") - new /obj/effect/spawner/newbomb/timer/syndicate(src.loc) - new /obj/item/clothing/head/collectable/petehat(src.loc) + new /obj/effect/spawner/newbomb/timer/syndicate(get_turf(src)) + new /obj/item/clothing/head/collectable/petehat(get_turf(src)) message_admins("[key_name_admin(usr)] has outbombed Cuban Pete and been awarded a bomb.") log_game("[key_name(usr)] has outbombed Cuban Pete and been awarded a bomb.") - src.New() + New() emagged = 0 else feedback_inc("arcade_win_normal") - prizevend() + var/score = player_hp + player_mp + 5 + prizevend(score) else if (emagged && (turtle >= 4)) var/boomamt = rand(5,10) - src.temp = "[src.enemy_name] throws a bomb, exploding you for [boomamt] damage!" + temp = "[enemy_name] throws a bomb, exploding you for [boomamt] damage!" playsound(src.loc, 'sound/arcade/Boom.ogg', 20, 1, extrarange = -6, falloff = 10) - src.player_hp -= boomamt + player_hp -= boomamt - else if ((src.enemy_mp <= 5) && (prob(70))) + else if ((enemy_mp <= 5) && (prob(70))) var/stealamt = rand(2,3) - src.temp = "[src.enemy_name] steals [stealamt] of your power!" + temp = "[enemy_name] steals [stealamt] of your power!" playsound(src.loc, 'sound/arcade/Steal.ogg', 20, 1, extrarange = -6, falloff = 10) - src.player_mp -= stealamt - src.updateUsrDialog() + player_mp -= stealamt + updateUsrDialog() - if (src.player_mp <= 0) - src.gameover = 1 + if (player_mp <= 0) + gameover = 1 sleep(10) - src.temp = "You have been drained! GAME OVER" + temp = "You have been drained! GAME OVER" playsound(src.loc, 'sound/arcade/Lose.ogg', 20, 1, extrarange = -6, falloff = 10) if(emagged) feedback_inc("arcade_loss_mana_emagged") @@ -257,21 +217,21 @@ else feedback_inc("arcade_loss_mana_normal") - else if ((src.enemy_hp <= 10) && (src.enemy_mp > 4)) - src.temp = "[src.enemy_name] heals for 4 health!" + else if ((enemy_hp <= 10) && (enemy_mp > 4)) + temp = "[enemy_name] heals for 4 health!" playsound(src.loc, 'sound/arcade/Heal.ogg', 20, 1, extrarange = -6, falloff = 10) - src.enemy_hp += 4 - src.enemy_mp -= 4 + enemy_hp += 4 + enemy_mp -= 4 else var/attackamt = rand(3,6) - src.temp = "[src.enemy_name] attacks for [attackamt] damage!" + temp = "[enemy_name] attacks for [attackamt] damage!" playsound(src.loc, 'sound/arcade/Hit.ogg', 20, 1, extrarange = -6, falloff = 10) - src.player_hp -= attackamt + player_hp -= attackamt - if ((src.player_mp <= 0) || (src.player_hp <= 0)) - src.gameover = 1 - src.temp = "You have been crushed! GAME OVER" + if ((player_mp <= 0) || (player_hp <= 0)) + gameover = 1 + temp = "You have been crushed! GAME OVER" playsound(src.loc, 'sound/arcade/Lose.ogg', 20, 1, extrarange = -6, falloff = 10) if(emagged) feedback_inc("arcade_loss_hp_emagged") @@ -279,7 +239,7 @@ else feedback_inc("arcade_loss_hp_normal") - src.blocked = 0 + blocked = 0 return @@ -298,7 +258,7 @@ enemy_name = "Cuban Pete" name = "Outbomb Cuban Pete" - src.updateUsrDialog() + updateUsrDialog() // *** THE ORION TRAIL ** // @@ -450,7 +410,7 @@ dat += "

Close

" var/datum/browser/popup = new(user, "arcade", "The Orion Trail",400,700) popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state)) + popup.set_title_image(user.browse_rsc_icon(icon, icon_state)) popup.open() return @@ -537,7 +497,7 @@ playsound(src.loc, 'sound/effects/bang.ogg', 20, 1) if(ORION_TRAIL_MALFUNCTION) playsound(src.loc, 'sound/effects/EMPulse.ogg', 20, 1) - src.visible_message("[src] malfunctions, randomizing in-game stats!") + visible_message("[src] malfunctions, randomizing in-game stats!") var/oldfood = food var/oldfuel = fuel food = rand(10,80) / rand(1,2) @@ -545,9 +505,9 @@ if(electronics) sleep(10) if(oldfuel > fuel && oldfood > food) - src.audible_message("[src] lets out a somehow reassuring chime.") + audible_message("[src] lets out a somehow reassuring chime.") else if(oldfuel < fuel || oldfood < food) - src.audible_message("[src] lets out a somehow ominous chime.") + audible_message("[src] lets out a somehow ominous chime.") food = oldfood fuel = oldfuel playsound(src.loc, 'sound/machines/chime.ogg', 20, 1) @@ -709,8 +669,8 @@ last_spaceport_action = "Traded Food for Fuel" event() - src.add_fingerprint(usr) - src.updateUsrDialog() + add_fingerprint(usr) + updateUsrDialog() busy = 0 return @@ -984,11 +944,12 @@ turns = 1 atom_say("Congratulations, you made it to Orion!") if(emagged) - new /obj/item/weapon/orion_ship(src.loc) + new /obj/item/weapon/orion_ship(get_turf(src)) message_admins("[key_name_admin(usr)] made it to Orion on an emagged machine and got an explosive toy ship.") log_game("[key_name(usr)] made it to Orion on an emagged machine and got an explosive toy ship.") else - prizevend() + var/score = alive + round(food/2) + round(fuel/5) + engine + hull + electronics - lings_aboard + prizevend(score) emagged = 0 name = "The Orion Trail" desc = "Learn how our ancestors got to Orion, and have fun in the process!" @@ -1047,17 +1008,17 @@ user << "You flip the switch on the underside of [src]." active = 1 - src.visible_message("[src] softly beeps and whirs to life!") + visible_message("[src] softly beeps and whirs to life!") playsound(src.loc, 'sound/machines/defib_SaftyOn.ogg', 25, 1) atom_say("This is ship ID #[rand(1,1000)] to Orion Port Authority. We're coming in for landing, over.") sleep(20) - src.visible_message("[src] begins to vibrate...") + visible_message("[src] begins to vibrate...") atom_say("Uh, Port? Having some issues with our reactor, could you check it out? Over.") sleep(30) atom_say("Oh, God! Code Eight! CODE EIGHT! IT'S GONNA BL-") playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 25, 1) sleep(3.6) - src.visible_message("[src] explodes!") + visible_message("[src] explodes!") explosion(src.loc, 1,2,4, flame_range = 3) qdel(src) diff --git a/code/game/machinery/computer/message.dm b/code/game/machinery/computer/message.dm index 0ebb13efcd6..72d01fda958 100644 --- a/code/game/machinery/computer/message.dm +++ b/code/game/machinery/computer/message.dm @@ -408,7 +408,10 @@ //Get out list of viable PDAs var/list/obj/item/device/pda/sendPDAs = list() for(var/obj/item/device/pda/P in PDAs) - if(!P.owner || P.toff || P.hidden) continue + var/datum/data/pda/app/messenger/PM = P.find_program(/datum/data/pda/app/messenger) + + if(!PM || !PM.can_receive()) + continue sendPDAs += P if(PDAs && PDAs.len > 0) customrecepient = input(usr, "Select a PDA from the list.") as null|anything in sortAtom(sendPDAs) @@ -426,7 +429,6 @@ //Send message if("Send") - if(isnull(customsender) || customsender == "") customsender = "UNKNOWN" @@ -438,36 +440,44 @@ message = "NOTICE: No message entered!" return src.attack_hand(usr) + var/datum/data/pda/app/messenger/recipient_messenger = customrecepient.find_program(/datum/data/pda/app/messenger) + + if(!recipient_messenger) + message = "ERROR: Message could not be transmitted!" + return src.attack_hand(usr) + var/obj/item/device/pda/PDARec = null for (var/obj/item/device/pda/P in PDAs) - if (!P.owner || P.toff || P.hidden) continue + var/datum/data/pda/app/messenger/PM = P.find_program(/datum/data/pda/app/messenger) + + if (!PM || !PM.can_receive()) + continue if(P.owner == customsender) PDARec = P + break //Sender isn't faking as someone who exists if(isnull(PDARec)) src.linkedServer.send_pda_message("[customrecepient.owner]", "[customsender]","[custommessage]") - customrecepient.play_ringtone() + recipient_messenger.play_ringtone() if( customrecepient.loc && ishuman(customrecepient.loc) ) var/mob/living/carbon/human/H = customrecepient.loc H << "\icon[customrecepient] Message from [customsender] ([customjob]), \"[custommessage]\" (Reply)" log_pda("[usr] (PDA: [customsender]) sent \"[custommessage]\" to [customrecepient.owner]") - customrecepient.overlays.Cut() - customrecepient.overlays += image('icons/obj/pda.dmi', "pda-r") + recipient_messenger.set_new(1) //Sender is faking as someone who exists else src.linkedServer.send_pda_message("[customrecepient.owner]", "[PDARec.owner]","[custommessage]") - customrecepient.tnote.Add(list(list("sent" = 0, "owner" = "[PDARec.owner]", "job" = "[customjob]", "message" = "[custommessage]", "target" ="\ref[PDARec]"))) + recipient_messenger.tnote.Add(list(list("sent" = 0, "owner" = "[PDARec.owner]", "job" = "[customjob]", "message" = "[custommessage]", "target" ="\ref[PDARec]"))) - if(!customrecepient.conversations.Find("\ref[PDARec]")) - customrecepient.conversations.Add("\ref[PDARec]") + if(!recipient_messenger.conversations.Find("\ref[PDARec]")) + recipient_messenger.conversations.Add("\ref[PDARec]") - customrecepient.play_ringtone() + recipient_messenger.play_ringtone() if( customrecepient.loc && ishuman(customrecepient.loc) ) var/mob/living/carbon/human/H = customrecepient.loc H << "\icon[customrecepient] Message from [PDARec.owner] ([customjob]), \"[custommessage]\" (Reply)" log_pda("[usr] (PDA: [PDARec.owner]) sent \"[custommessage]\" to [customrecepient.owner]") - customrecepient.overlays.Cut() - customrecepient.overlays += image('icons/obj/pda.dmi', "pda-r") + recipient_messenger.set_new(1) //Finally.. ResetMessage() diff --git a/code/game/machinery/computer/power.dm b/code/game/machinery/computer/power.dm index a549dd5b64d..ca3c1f84410 100644 --- a/code/game/machinery/computer/power.dm +++ b/code/game/machinery/computer/power.dm @@ -16,6 +16,9 @@ power_monitors += src power_monitors = sortAtom(power_monitors) power_monitor = new(src) + +/obj/machinery/computer/monitor/initialize() + ..() powermonitor_repository.update_cache() powernet = find_powernet() diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index f4c6cc90c57..c62c8131f25 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -844,7 +844,18 @@ obj/item/weapon/circuitboard/rdserver board_type = "machine" origin_tech = "programming=2" req_components = list( - /obj/item/weapon/stock_parts.matter_bin = 1, + /obj/item/weapon/stock_parts/matter_bin = 1, /obj/item/weapon/stock_parts/manipulator = 1, /obj/item/stack/cable_coil = 5, - /obj/item/stack/sheet/glass = 1) \ No newline at end of file + /obj/item/stack/sheet/glass = 1) + +/obj/item/weapon/circuitboard/prize_counter + name = "circuit board (Prize Counter)" + build_path = /obj/machinery/prize_counter + board_type = "machine" + origin_tech = "programming=2;materials=2" + req_components = list( + /obj/item/weapon/stock_parts/matter_bin = 1, + /obj/item/weapon/stock_parts/manipulator = 1, + /obj/item/weapon/stock_parts/console_screen = 1, + /obj/item/stack/cable_coil = 1) \ No newline at end of file diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index 0939b189eb1..fbc80b869ad 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -323,7 +323,9 @@ */ /obj/machinery/vending/proc/pay_with_card(var/obj/item/weapon/card/id/I) visible_message("[usr] swipes a card through [src].") - var/datum/money_account/customer_account = attempt_account_access_nosec(I.associated_account_number) + return pay_with_account(get_card_account(I)) + +/obj/machinery/vending/proc/pay_with_account(var/datum/money_account/customer_account) if (!customer_account) src.status_message = "Error: Unable to access account. Please contact technical support if problem persists." src.status_error = 1 @@ -338,7 +340,7 @@ // empty at high security levels if(customer_account.security_level != 0) //If card requires pin authentication (ie seclevel 1 or 2) var/attempt_pin = input("Enter pin code", "Vendor transaction") as num - customer_account = attempt_account_access(I.associated_account_number, attempt_pin, 2) + customer_account = attempt_account_access(customer_account, attempt_pin, 2) if(!customer_account) src.status_message = "Unable to access account: incorrect credentials." @@ -351,28 +353,18 @@ return 0 else // Okay to move the money at this point + var/paid = customer_account.charge(currently_vending.price, + transaction_purpose = "Purchase of [currently_vending.product_name]", + terminal_name = name, + terminal_id = name, + dest_name = vendor_account.owner_name) - // debit money from the purchaser's account - customer_account.money -= currently_vending.price - - // create entry in the purchaser's account log - var/datum/transaction/T = new() - T.target_name = "[vendor_account.owner_name] (via [src.name])" - T.purpose = "Purchase of [currently_vending.product_name]" - if(currently_vending.price > 0) - T.amount = "([currently_vending.price])" - else - T.amount = "[currently_vending.price]" - T.source_terminal = src.name - T.date = current_date_string - T.time = worldtime2text() - customer_account.transaction_log.Add(T) - - // Give the vendor the money. We use the account owner name, which means - // that purchases made with stolen/borrowed card will look like the card - // owner made them - credit_purchase(customer_account.owner_name) - return 1 + if(paid) + // Give the vendor the money. We use the account owner name, which means + // that purchases made with stolen/borrowed card will look like the card + // owner made them + credit_purchase(customer_account.owner_name) + return paid /** * Add money for current purchase to the vendor account. @@ -471,38 +463,28 @@ if (href_list["pay"]) if(currently_vending && vendor_account && !vendor_account.suspended) - if(istype(usr, /mob/living/carbon/human)) - var/paid = 0 - var/handled = 0 - var/mob/living/carbon/human/H = usr - var/obj/item/weapon/card/card = null - if(istype(H.wear_id,/obj/item/weapon/card)) - card = H.wear_id - paid = pay_with_card(card) - handled = 1 - else if(istype(H.get_active_hand(), /obj/item/weapon/card)) - card = H.get_active_hand() - paid = pay_with_card(card) - handled = 1 - if(paid) - src.vend(currently_vending, usr) - return - else if(handled) - nanomanager.update_uis(src) - return // don't smack that machine with your 2 credits + var/paid = 0 + var/handled = 0 + var/datum/money_account/A = usr.get_worn_id_account() + if(A) + paid = pay_with_account(A) + handled = 1 + else if(istype(usr.get_active_hand(), /obj/item/weapon/card)) + paid = pay_with_card(usr.get_active_hand()) + handled = 1 + if(paid) + src.vend(currently_vending, usr) + return + else if(handled) + nanomanager.update_uis(src) + return // don't smack that machine with your 2 credits if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf)))) if ((href_list["vend"]) && (src.vend_ready) && (!currently_vending)) - if(istype(usr,/mob/living/silicon)) - if(istype(usr,/mob/living/silicon/robot)) - var/mob/living/silicon/robot/R = usr - if(!(R.module && istype(R.module,/obj/item/weapon/robot_module/butler) )) - usr << "\red The vending machine refuses to interface with you, as you are not in its target demographic!" - return - else - usr << "\red The vending machine refuses to interface with you, as you are not in its target demographic!" - return + if(issilicon(usr) && !isrobot(usr)) + usr << "The vending machine refuses to interface with you, as you are not in its target demographic!" + return if((!allowed(usr)) && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH usr << "Access denied." //Unless emagged of course @@ -836,11 +818,11 @@ icon_deny = "cart-deny" products = list(/obj/item/device/pda =10,/obj/item/weapon/cartridge/medical = 10,/obj/item/weapon/cartridge/chemistry = 10, /obj/item/weapon/cartridge/engineering = 10,/obj/item/weapon/cartridge/atmos = 10,/obj/item/weapon/cartridge/janitor = 10, - /obj/item/weapon/cartridge/signal/toxins = 10,/obj/item/weapon/cartridge/signal = 10,/obj/item/weapon/cartridge = 10) + /obj/item/weapon/cartridge/signal/toxins = 10,/obj/item/weapon/cartridge/signal = 10) contraband = list(/obj/item/weapon/cartridge/clown = 1,/obj/item/weapon/cartridge/mime = 1) prices = list(/obj/item/device/pda =300,/obj/item/weapon/cartridge/medical = 200,/obj/item/weapon/cartridge/chemistry = 150,/obj/item/weapon/cartridge/engineering = 100, /obj/item/weapon/cartridge/atmos = 75,/obj/item/weapon/cartridge/janitor = 100,/obj/item/weapon/cartridge/signal/toxins = 150, - /obj/item/weapon/cartridge/signal = 75,/obj/item/weapon/cartridge = 50) + /obj/item/weapon/cartridge/signal = 75) /obj/machinery/vending/liberationstation @@ -1096,7 +1078,7 @@ icon_state = "engivend" icon_deny = "engivend-deny" req_access_txt = "11" //Engineering Equipment access - products = list(/obj/item/clothing/glasses/meson = 2,/obj/item/device/multitool = 4,/obj/item/weapon/airlock_electronics = 10,/obj/item/weapon/firealarm_electronics = 10,/obj/item/weapon/apc_electronics = 10,/obj/item/weapon/airalarm_electronics = 10,/obj/item/weapon/stock_parts/cell/high = 10) + products = list(/obj/item/clothing/glasses/meson = 2,/obj/item/device/multitool = 4,/obj/item/weapon/airlock_electronics = 10,/obj/item/weapon/firealarm_electronics = 10,/obj/item/weapon/apc_electronics = 10,/obj/item/weapon/airalarm_electronics = 10,/obj/item/weapon/stock_parts/cell/high = 10,/obj/item/weapon/camera_assembly = 10) contraband = list(/obj/item/weapon/stock_parts/cell/potato = 3) premium = list(/obj/item/weapon/storage/belt/utility = 3) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 15d322aeaba..d8d0d34eed5 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -49,6 +49,8 @@ var/list/allowed = null //suit storage stuff. var/obj/item/device/uplink/hidden/hidden_uplink = null // All items can have an uplink hidden inside, just remember to add the triggers. + var/needs_permit = 0 //Used by security bots to determine if this item is safe for public use. + var/strip_delay = DEFAULT_ITEM_STRIP_DELAY var/put_on_delay = DEFAULT_ITEM_PUTON_DELAY diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm deleted file mode 100755 index 697e2c9e867..00000000000 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ /dev/null @@ -1,1275 +0,0 @@ - -//The advanced pea-green monochrome lcd of tomorrow. - -var/global/list/obj/item/device/pda/PDAs = list() - - -/obj/item/device/pda - name = "PDA" - desc = "A portable microcomputer by Thinktronic Systems, LTD. Functionality determined by a preprogrammed ROM cartridge." - icon = 'icons/obj/pda.dmi' - icon_state = "pda" - item_state = "electronic" - w_class = 1.0 - slot_flags = SLOT_PDA | SLOT_BELT - - //Main variables - var/owner = null - var/default_cartridge = 0 // Access level defined by cartridge - var/obj/item/weapon/cartridge/cartridge = null //current cartridge - var/mode = 0 //Controls what menu the PDA will display. 0 is hub; the rest are either built in or based on cartridge. - - var/lastmode = 0 - var/ui_tick = 0 - - //Secondary variables - var/scanmode = 0 //1 is medical scanner, 2 is forensics, 3 is reagent scanner. - var/fon = 0 //Is the flashlight function on? - var/f_lum = 2 //Luminosity for the flashlight function - var/silent = 0 //To beep or not to beep, that is the question - var/toff = 0 //If 1, messenger disabled - var/tnote[0] //Current Texts - var/last_text //No text spamming - var/last_honk //Also no honk spamming that's bad too - - var/ttone = "beep" //The ringtone! - var/list/ttone_sound = list("beep" = 'sound/machines/twobeep.ogg', - "boom" = 'sound/effects/explosionfar.ogg', - "slip" = 'sound/misc/slip.ogg', - "honk" = 'sound/items/bikehorn.ogg', - "SKREE" = 'sound/voice/shriek1.ogg', - "holy" = 'sound/items/PDA/ambicha4-short.ogg', - "xeno" = 'sound/voice/hiss1.ogg') - - var/lock_code = "" // Lockcode to unlock uplink - var/honkamt = 0 //How many honks left when infected with honk.exe - var/mimeamt = 0 //How many silence left when infected with mime.exe - var/note = "Congratulations, your station has chosen the Thinktronic 5230 Personal Data Assistant!" //Current note in the notepad function - var/notehtml = "" - var/cart = "" //A place to stick cartridge menu information - var/detonate = 1 // Can the PDA be blown up? - var/hidden = 0 // Is the PDA hidden from the PDA list? - var/active_conversation = null // New variable that allows us to only view a single conversation. - var/list/conversations = list() // For keeping up with who we have PDA messsages from. - var/newmessage = 0 //To remove hackish overlay check - - var/list/cartmodes = list(40, 42, 43, 433, 44, 441, 45, 451, 46, 48, 47, 49) // If you add more cartridge modes add them to this list as well. - var/list/no_auto_update = list(1, 40, 43, 44, 441, 45, 451) // These modes we turn off autoupdate - var/list/update_every_five = list(3, 41, 433, 46, 47, 48, 49) // These we update every 5 ticks - - var/obj/item/weapon/card/id/id = null //Making it possible to slot an ID card into the PDA so it can function as both. - var/ownjob = null //related to above - var/ownrank = null // this one is rank, never alt title - - var/obj/item/device/paicard/pai = null // A slot for a personal AI device - var/retro_mode = 0 - -/obj/item/device/pda/medical - default_cartridge = /obj/item/weapon/cartridge/medical - icon_state = "pda-medical" - -/obj/item/device/pda/viro - default_cartridge = /obj/item/weapon/cartridge/medical - icon_state = "pda-virology" - -/obj/item/device/pda/engineering - default_cartridge = /obj/item/weapon/cartridge/engineering - icon_state = "pda-engineer" - -/obj/item/device/pda/security - default_cartridge = /obj/item/weapon/cartridge/security - icon_state = "pda-security" - -/obj/item/device/pda/detective - default_cartridge = /obj/item/weapon/cartridge/detective - icon_state = "pda-security" - -/obj/item/device/pda/warden - default_cartridge = /obj/item/weapon/cartridge/security - icon_state = "pda-warden" - -/obj/item/device/pda/janitor - default_cartridge = /obj/item/weapon/cartridge/janitor - icon_state = "pda-janitor" - ttone = "slip" - -/obj/item/device/pda/toxins - default_cartridge = /obj/item/weapon/cartridge/signal/toxins - icon_state = "pda-science" - ttone = "boom" - -/obj/item/device/pda/clown - default_cartridge = /obj/item/weapon/cartridge/clown - icon_state = "pda-clown" - desc = "A portable microcomputer by Thinktronic Systems, LTD. The surface is coated with polytetrafluoroethylene and banana drippings." - ttone = "honk" - -/obj/item/device/pda/mime - default_cartridge = /obj/item/weapon/cartridge/mime - icon_state = "pda-mime" - silent = 1 - ttone = "silence" - -/obj/item/device/pda/heads - default_cartridge = /obj/item/weapon/cartridge/head - icon_state = "pda-h" - -/obj/item/device/pda/heads/hop - default_cartridge = /obj/item/weapon/cartridge/hop - icon_state = "pda-hop" - -/obj/item/device/pda/heads/hos - default_cartridge = /obj/item/weapon/cartridge/hos - icon_state = "pda-hos" - -/obj/item/device/pda/heads/ce - default_cartridge = /obj/item/weapon/cartridge/ce - icon_state = "pda-ce" - -/obj/item/device/pda/heads/cmo - default_cartridge = /obj/item/weapon/cartridge/cmo - icon_state = "pda-cmo" - -/obj/item/device/pda/heads/rd - default_cartridge = /obj/item/weapon/cartridge/rd - icon_state = "pda-rd" - -/obj/item/device/pda/captain - default_cartridge = /obj/item/weapon/cartridge/captain - icon_state = "pda-captain" - detonate = 0 - //toff = 1 - -/obj/item/device/pda/heads/ntrep - default_cartridge = /obj/item/weapon/cartridge/supervisor - icon_state = "pda-h" - -/obj/item/device/pda/heads/magistrate - default_cartridge = /obj/item/weapon/cartridge/supervisor - icon_state = "pda-h" - -/obj/item/device/pda/heads/blueshield - default_cartridge = /obj/item/weapon/cartridge/hos - icon_state = "pda-h" - -/obj/item/device/pda/cargo - default_cartridge = /obj/item/weapon/cartridge/quartermaster - icon_state = "pda-cargo" - -/obj/item/device/pda/quartermaster - default_cartridge = /obj/item/weapon/cartridge/quartermaster - icon_state = "pda-qm" - -/obj/item/device/pda/shaftminer - icon_state = "pda-miner" - -/obj/item/device/pda/syndicate - default_cartridge = /obj/item/weapon/cartridge/syndicate - icon_state = "pda-syndi" - name = "Military PDA" - owner = "John Doe" - hidden = 1 - -/obj/item/device/pda/chaplain - icon_state = "pda-chaplain" - ttone = "holy" - -/obj/item/device/pda/lawyer - default_cartridge = /obj/item/weapon/cartridge/lawyer - icon_state = "pda-lawyer" - ttone = "..." - -/obj/item/device/pda/botanist - //default_cartridge = /obj/item/weapon/cartridge/botanist - icon_state = "pda-hydro" - -/obj/item/device/pda/roboticist - icon_state = "pda-roboticist" - -/obj/item/device/pda/librarian - icon_state = "pda-library" - desc = "A portable microcomputer by Thinktronic Systems, LTD. This is model is a WGW-11 series e-reader." - note = "Congratulations, your station has chosen the Thinktronic 5290 WGW-11 Series E-reader and Personal Data Assistant!" - silent = 1 //Quiet in the library! - -/obj/item/device/pda/clear - icon_state = "pda-transp" - desc = "A portable microcomputer by Thinktronic Systems, LTD. This is model is a special edition with a transparent case." - note = "Congratulations, you have chosen the Thinktronic 5230 Personal Data Assistant Deluxe Special Max Turbo Limited Edition!" - -/obj/item/device/pda/chef - icon_state = "pda-chef" - -/obj/item/device/pda/bar - icon_state = "pda-bartender" - -/obj/item/device/pda/atmos - default_cartridge = /obj/item/weapon/cartridge/atmos - icon_state = "pda-atmos" - -/obj/item/device/pda/chemist - default_cartridge = /obj/item/weapon/cartridge/chemistry - icon_state = "pda-chemistry" - -/obj/item/device/pda/geneticist - default_cartridge = /obj/item/weapon/cartridge/medical - icon_state = "pda-genetics" - -/obj/item/device/pda/centcom - default_cartridge = /obj/item/weapon/cartridge/centcom - icon_state = "pda-h" - - -// Special AI/pAI PDAs that cannot explode. -/obj/item/device/pda/ai - icon_state = "NONE" - ttone = "data" - detonate = 0 - - -/obj/item/device/pda/ai/proc/set_name_and_job(newname as text, newjob as text, newrank as null|text) - owner = newname - ownjob = newjob - if(newrank) - ownrank = newrank - else - ownrank = ownjob - name = newname + " (" + ownjob + ")" - - -//AI verb and proc for sending PDA messages. -/mob/living/silicon/ai/proc/cmd_send_pdamesg(mob/user as mob) - if(user.stat == 2) - user << "You can't send PDA messages because you are dead!" - return - var/list/plist = aiPDA.available_pdas() - if (plist) - var/c = input(user, "Please select a PDA") as null|anything in sortList(plist) - if (!c) // if the user hasn't selected a PDA file we can't send a message - return - var/selected = plist[c] - aiPDA.create_message(user, selected) - -/mob/living/silicon/ai/proc/cmd_show_message_log(mob/user as mob) - if(user.stat == 2) - user << "You can't do that because you are dead!" - return - var/HTML = "AI PDA Message Log" - for(var/index in aiPDA.tnote) - if(index["sent"]) - HTML += addtext("→ To ", index["owner"],":
", index["message"], "
") - else - HTML += addtext("← From ", index["owner"],":
", index["message"], "
") - HTML +="" - user << browse(HTML, "window=log;size=400x444;border=1;can_resize=1;can_close=1;can_minimize=0") - -/obj/item/device/pda/ai/verb/cmd_send_pdamesg() - set category = "AI IM" - set name = "Send PDA Message" - set src in usr - if(usr.stat == 2) - usr << "You can't send PDA messages because you are dead!" - return - var/list/plist = available_pdas() - if (plist) - var/c = input(usr, "Please select a PDA") as null|anything in sortList(plist) - if (!c) // if the user hasn't selected a PDA file we can't send a message - return - var/selected = plist[c] - create_message(usr, selected) - -/obj/item/device/pda/ai/verb/cmd_show_message_log() - set category = "AI IM" - set name = "Show Message Log" - set src in usr - if(usr.stat == 2) - usr << "You can't do that because you are dead!" - return - var/HTML = "AI PDA Message Log" - for(var/index in tnote) - if(index["sent"]) - HTML += addtext("→ To ", index["owner"],":
", index["message"], "
") - else - HTML += addtext("← From ", index["owner"],":
", index["message"], "
") - HTML +="" - usr << browse(HTML, "window=log;size=400x444;border=1;can_resize=1;can_close=1;can_minimize=0") - -/obj/item/device/pda/ai/verb/cmd_toggle_pda_receiver() - set category = "AI IM" - set name = "Toggle Sender/Receiver" - set src in usr - if(usr.stat == 2) - usr << "You can't do that because you are dead!" - return - toff = !toff - usr << "PDA sender/receiver toggled [(toff ? "Off" : "On")]!" - - -/obj/item/device/pda/ai/verb/cmd_toggle_pda_silent() - set category = "AI IM" - set name = "Toggle Ringer" - set src in usr - if(usr.stat == 2) - usr << "You can't do that because you are dead!" - return - silent=!silent - usr << "PDA ringer toggled [(silent ? "Off" : "On")]!" - -/obj/item/device/pda/ai/can_use() - return 1 - - -/obj/item/device/pda/ai/attack_self(mob/user as mob) - if ((honkamt > 0) && (prob(60)))//For clown virus. - honkamt-- - playsound(loc, 'sound/items/bikehorn.ogg', 30, 1) - return - - -/obj/item/device/pda/ai/pai - ttone = "assist" - - -/* - * The Actual PDA - */ -/obj/item/device/pda/New() - ..() - PDAs += src - PDAs = sortAtom(PDAs) - if(default_cartridge) - cartridge = new default_cartridge(src) - new /obj/item/weapon/pen(src) - -/obj/item/device/pda/proc/can_use() - - if(!ismob(loc)) - return 0 - - var/mob/M = loc - if(M.stat || M.restrained() || M.paralysis || M.stunned || M.weakened) - return 0 - if((src in M.contents) || ( istype(loc, /turf) && in_range(src, M) )) - return 1 - else - return 0 - -/obj/item/device/pda/GetAccess() - if(id) - return id.GetAccess() - else - return ..() - -/obj/item/device/pda/GetID() - return id - -/obj/item/device/pda/MouseDrop(obj/over_object as obj, src_location, over_location) - var/mob/M = usr - if((!istype(over_object, /obj/screen)) && can_use()) - return attack_self(M) - return - - -/obj/item/device/pda/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - ui_tick++ - var/datum/nanoui/old_ui = nanomanager.get_open_ui(user, src, "main") - var/auto_update = 1 - if(mode in no_auto_update) - auto_update = 0 - if(old_ui && (mode == lastmode && ui_tick % 5 && mode in update_every_five)) - return - - lastmode = mode - - var/title = "Personal Data Assistant" - - var/data[0] // This is the data that will be sent to the PDA - - - data["owner"] = owner // Who is your daddy... - data["ownjob"] = ownjob // ...and what does he do? - - data["mode"] = mode // The current view - data["scanmode"] = scanmode // Scanners - data["fon"] = fon // Flashlight on? - data["pai"] = (isnull(pai) ? 0 : 1) // pAI inserted? - data["note"] = note // current pda notes - data["silent"] = silent // does the pda make noise when it receives a message? - data["toff"] = toff // is the messenger function turned off? - data["active_conversation"] = active_conversation // Which conversation are we following right now? - - - data["idInserted"] = (id ? 1 : 0) - data["idLink"] = (id ? text("[id.registered_name], [id.assignment]") : "--------") - - data["useRetro"] = retro_mode - - data["cart_loaded"] = cartridge ? 1:0 - if(cartridge) - var/cartdata[0] - - cartdata["access"] = list(\ - "access_security" = cartridge.access_security,\ - "access_engine" = cartridge.access_engine,\ - "access_atmos" = cartridge.access_atmos,\ - "access_medical" = cartridge.access_medical,\ - "access_clown" = cartridge.access_clown,\ - "access_mime" = cartridge.access_mime,\ - "access_janitor" = cartridge.access_janitor,\ - "access_quartermaster" = cartridge.access_quartermaster,\ - "access_hydroponics" = cartridge.access_hydroponics,\ - "access_reagent_scanner" = cartridge.access_reagent_scanner,\ - "access_remote_door" = cartridge.access_remote_door,\ - "access_status_display" = cartridge.access_status_display,\ - "access_detonate_pda" = cartridge.access_detonate_pda\ - ) - - if(mode in cartmodes) - data["records"] = cartridge.create_NanoUI_values() - - if(mode == 0) - cartdata["name"] = cartridge.name - if(isnull(cartridge.radio)) - cartdata["radio"] = 0 - else - if(istype(cartridge.radio, /obj/item/radio/integrated/beepsky)) - cartdata["radio"] = 1 - if(istype(cartridge.radio, /obj/item/radio/integrated/signal)) - cartdata["radio"] = 2 - if(istype(cartridge.radio, /obj/item/radio/integrated/mule)) - cartdata["radio"] = 3 - - if(mode == 2) - cartdata["charges"] = cartridge.charges ? cartridge.charges : 0 - data["cartridge"] = cartdata - data["stationTime"] = worldtime2text() - data["newMessage"] = newmessage - - if(mode==2) - var/convopdas[0] - var/pdas[0] - var/count = 0 - for (var/obj/item/device/pda/P in PDAs) - if (!P.owner||P.toff||P == src||P.hidden) continue - if(conversations.Find("\ref[P]")) - convopdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "1"))) - else - pdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "0"))) - count++ - - data["convopdas"] = convopdas - data["pdas"] = pdas - data["pda_count"] = count - - if(mode==21) - data["messagescount"] = tnote.len - data["messages"] = tnote - else - data["messagescount"] = null - data["messages"] = null - - if(active_conversation) - for(var/c in tnote) - if(c["target"] == active_conversation) - data["convo_name"] = sanitize(c["owner"]) - data["convo_job"] = sanitize(c["job"]) - break - if(mode==41) - data_core.get_manifest_json() - - - if(mode==3) - var/turf/T = get_turf(user.loc) - if(!isnull(T)) - var/datum/gas_mixture/environment = T.return_air() - - var/pressure = environment.return_pressure() - var/total_moles = environment.total_moles() - - if (total_moles) - var/o2_level = environment.oxygen/total_moles - var/n2_level = environment.nitrogen/total_moles - var/co2_level = environment.carbon_dioxide/total_moles - var/plasma_level = environment.toxins/total_moles - var/unknown_level = 1-(o2_level+n2_level+co2_level+plasma_level) - data["aircontents"] = list(\ - "pressure" = "[round(pressure,0.1)]",\ - "nitrogen" = "[round(n2_level*100,0.1)]",\ - "oxygen" = "[round(o2_level*100,0.1)]",\ - "carbon_dioxide" = "[round(co2_level*100,0.1)]",\ - "plasma" = "[round(plasma_level*100,0.01)]",\ - "other" = "[round(unknown_level, 0.01)]",\ - "temp" = "[round(environment.temperature-T0C,0.1)]",\ - "reading" = 1\ - ) - if(isnull(data["aircontents"])) - - data["aircontents"] = list("reading" = 0) - - - data["manifest"] = list("__json_cache" = ManifestJSON) - - // update the ui if it exists, returns null if no ui is passed/found - ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "pda.tmpl", title, 630, 600, state = inventory_state) - - // when the ui is first opened this is the data it will use - ui.set_initial_data(data) - // open the new ui window - ui.open() - // auto update every Master Controller tick - ui.set_auto_update(auto_update) - -//NOTE: graphic resources are loaded on client login -/obj/item/device/pda/attack_self(mob/user as mob) - user.set_machine(src) - if(active_uplink_check(user)) - return - ui_interact(user) //NanoUI requires this proc - return - -/obj/item/device/pda/Topic(href, href_list) - if(href_list["cartmenu"] && !isnull(cartridge)) - cartridge.Topic(href, href_list) - return 1 - if(href_list["radiomenu"] && !isnull(cartridge) && !isnull(cartridge.radio)) - cartridge.radio.Topic(href, href_list) - return 1 - - - ..() - var/mob/user = usr - var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, "main") - var/mob/living/U = usr - //Looking for master was kind of pointless since PDAs don't appear to have one. - //if ((src in U.contents) || ( istype(loc, /turf) && in_range(src, U) ) ) - if (usr.stat == DEAD) - return 0 - if(!can_use()) //Why reinvent the wheel? There's a proc that does exactly that. - U.unset_machine() - if(ui) - ui.close() - return 0 - - add_fingerprint(U) - U.set_machine(src) - - switch(href_list["choice"]) - -//BASIC FUNCTIONS=================================== - - if("Close")//Self explanatory - U.unset_machine() - ui.close() - return 0 - if("Refresh")//Refresh, goes to the end of the proc. - if("Return")//Return - if(mode<=9) - mode = 0 - else - mode = round(mode/10) - if(mode==2) - active_conversation = null - if(mode==4)//Fix for cartridges. Redirects to hub. - mode = 0 - else if(mode >= 40 && mode <= 49)//Fix for cartridges. Redirects to refresh the menu. - cartridge.mode = mode - if("Retro") - retro_mode = !retro_mode - ui_interact(user) - if ("Authenticate")//Checks for ID - id_check(U, 1) - if("UpdateInfo") - ownjob = id.assignment - ownrank = id.rank - name = "PDA-[owner] ([ownjob])" - if("Eject")//Ejects the cart, only done from hub. - if (!isnull(cartridge)) - var/turf/T = loc - if(ismob(T)) - T = T.loc - cartridge.loc = T - mode = 0 - scanmode = 0 - if (cartridge.radio) - cartridge.radio.hostpda = null - cartridge = null - -//MENU FUNCTIONS=================================== - - if("0")//Hub - mode = 0 - if("1")//Notes - mode = 1 - if("2")//Messenger - mode = 2 - if("21")//Read messages - mode = 21 - if("3")//Atmos scan - mode = 3 - if("4")//Redirects to hub - mode = 0 - if("chatroom") // chatroom hub - mode = 5 - if("41") //Manifest - mode = 41 - - -//MAIN FUNCTIONS=================================== - - if("Light") - if(fon) - fon = 0 - set_light(0) - else - fon = 1 - set_light(f_lum) - if("Medical Scan") - if(scanmode == 1) - scanmode = 0 - else if((!isnull(cartridge)) && (cartridge.access_medical)) - scanmode = 1 - if("Reagent Scan") - if(scanmode == 3) - scanmode = 0 - else if((!isnull(cartridge)) && (cartridge.access_reagent_scanner)) - scanmode = 3 - if("Halogen Counter") - if(scanmode == 4) - scanmode = 0 - else if((!isnull(cartridge)) && (cartridge.access_engine)) - scanmode = 4 - if("Honk") - if ( !(last_honk && world.time < last_honk + 20) ) - playsound(loc, 'sound/items/bikehorn.ogg', 50, 1) - last_honk = world.time - if("Gas Scan") - if(scanmode == 5) - scanmode = 0 - else if((!isnull(cartridge)) && (cartridge.access_atmos)) - scanmode = 5 - -//MESSENGER/NOTE FUNCTIONS=================================== - - if ("Edit") - var/n = input(U, "Please enter message", name, notehtml) as message - if (in_range(src, U) && loc == U) - n = copytext(adminscrub(n), 1, MAX_MESSAGE_LEN) - if (mode == 1) - note = html_decode(n) - notehtml = note - note = replacetext(note, "\n", "
") - else - ui.close() - if("Toggle Messenger") - toff = !toff - if("Toggle Ringer")//If viewing texts then erase them, if not then toggle silent status - silent = !silent - if("Clear")//Clears messages - if(href_list["option"] == "All") - tnote.Cut() - conversations.Cut() - if(href_list["option"] == "Convo") - var/new_tnote[0] - for(var/i in tnote) - if(i["target"] != active_conversation) - new_tnote[++new_tnote.len] = i - tnote = new_tnote - conversations.Remove(active_conversation) - - active_conversation = null - if(mode==21) - mode=2 - - if("Ringtone") - var/t = input(U, "Please enter new ringtone", name, ttone) as text - if (in_range(src, U) && loc == U) - if (t) - if(src.hidden_uplink && hidden_uplink.check_trigger(U, lowertext(t), lowertext(lock_code))) - U << "The PDA softly beeps." - ui.close() - else - t = sanitize(copytext(t, 1, 20)) - ttone = t - else - ui.close() - return 0 - if("Message") - - var/obj/item/device/pda/P = locate(href_list["target"]) - src.create_message(U, P) - if(mode == 2) - if(href_list["target"] in conversations) // Need to make sure the message went through, if not welp. - active_conversation = href_list["target"] - mode = 21 - - if("Select Conversation") - var/P = href_list["convo"] - for(var/n in conversations) - if(P == n) - active_conversation=P - mode=21 - if("Send Honk")//Honk virus - if(istype(cartridge, /obj/item/weapon/cartridge/clown))//Cartridge checks are kind of unnecessary since everything is done through switch. - var/obj/item/device/pda/P = locate(href_list["target"])//Leaving it alone in case it may do something useful, I guess. - if(!isnull(P)) - if (!P.toff && cartridge.charges > 0) - cartridge.charges-- - U.show_message("\blue Virus sent!", 1) - P.honkamt = (rand(15,20)) - else - U << "PDA not found." - else - ui.close() - return 0 - if("Send Silence")//Silent virus - if(istype(cartridge, /obj/item/weapon/cartridge/mime)) - var/obj/item/device/pda/P = locate(href_list["target"]) - if(!isnull(P)) - if (!P.toff && cartridge.charges > 0) - cartridge.charges-- - U.show_message("\blue Virus sent!", 1) - P.silent = 1 - P.ttone = "silence" - else - U << "PDA not found." - else - ui.close() - return 0 - - -//SYNDICATE FUNCTIONS=================================== - - if("Toggle Door") - if(cartridge && cartridge.access_remote_door) - for(var/obj/machinery/door/poddoor/M in world) - if(M.id_tag == cartridge.remote_door_id) - if(M.density) - M.open() - else - M.close() - - if("Detonate")//Detonate PDA - if(istype(cartridge, /obj/item/weapon/cartridge/syndicate)) - var/obj/item/device/pda/P = locate(href_list["target"]) - if(!isnull(P)) - if (!P.toff && cartridge.charges > 0) - cartridge.charges-- - - var/difficulty = 0 - - if(P.cartridge) - difficulty += P.cartridge.access_medical - difficulty += P.cartridge.access_security - difficulty += P.cartridge.access_engine - difficulty += P.cartridge.access_clown - difficulty += P.cartridge.access_janitor - else - difficulty += 2 - - if(prob(difficulty * 12) || (P.hidden_uplink)) - U.show_message("\red An error flashes on your [src].", 1) - else if (prob(difficulty * 3)) - U.show_message("\red Energy feeds back into your [src]!", 1) - ui.close() - explode() - log_admin("[key_name(U)] just attempted to blow up [P] with the Detomatix cartridge but failed, blowing themselves up") - message_admins("[key_name_admin(U)] just attempted to blow up [P] with the Detomatix cartridge but failed, blowing themselves up", 1) - else - U.show_message("\blue Success!", 1) - log_admin("[key_name(U)] just attempted to blow up [P] with the Detomatix cartridge and succeded") - message_admins("[key_name_admin(U)] just attempted to blow up [P] with the Detomatix cartridge and succeded", 1) - P.explode() - else - U << "PDA not found." - else - U.unset_machine() - ui.close() - return 0 - -//pAI FUNCTIONS=================================== - if("pai") - if(pai) - if(pai.loc != src) - pai = null - else - switch(href_list["option"]) - if("1") // Configure pAI device - pai.attack_self(U) - if("2") // Eject pAI device - var/turf/T = get_turf_or_move(src.loc) - if(T) - pai.loc = T - pai = null - - else - mode = text2num(href_list["choice"]) - if(cartridge) - cartridge.mode = mode - -//EXTRA FUNCTIONS=================================== - - if (mode == 2||mode == 21)//To clear message overlays. - overlays.Cut() - newmessage = 0 - - if ((honkamt > 0) && (prob(60)))//For clown virus. - honkamt-- - playsound(loc, 'sound/items/bikehorn.ogg', 30, 1) - - return 1 // return 1 tells it to refresh the UI in NanoUI - -/obj/item/device/pda/verb/verb_reset_pda() - set category = "Object" - set name = "Reset PDA" - set src in usr - - if(issilicon(usr)) - return - - if(can_use(usr)) - mode = 0 - nanomanager.update_uis(src) - usr << "You press the reset button on \the [src]." - else - usr << "You cannot do this while restrained." - -/obj/item/device/pda/proc/remove_id() - if (id) - if (ismob(loc)) - var/mob/M = loc - M.put_in_hands(id) - usr << "You remove the ID from the [name]." - else - id.loc = get_turf(src) - id = null - -/obj/item/device/pda/proc/create_message(var/mob/living/U = usr, var/obj/item/device/pda/P) - - var/t = input(U, "Please enter message", name, null) as text|null - if(!t) - return - t = sanitize(copytext(t, 1, MAX_MESSAGE_LEN)) - t = readd_quotes(t) - if (!t || !istype(P)) - return - if (!in_range(src, U) && loc != U) - return - - if (isnull(P)||P.toff || toff) - return - - if (last_text && world.time < last_text + 5) - return - - if(!can_use()) - return - - last_text = world.time - // check if telecomms I/O route 1459 is stable - //var/telecomms_intact = telecomms_process(P.owner, owner, t) - var/obj/machinery/message_server/useMS = null - if(message_servers) - for (var/obj/machinery/message_server/MS in message_servers) - //PDAs are now dependent on the Message Server. - if(MS.active) - useMS = MS - break - - var/datum/signal/signal = src.telecomms_process() - - var/useTC = 0 - if(signal) - if(signal.data["done"]) - useTC = 1 - var/turf/pos = get_turf(P) - if(pos.z in signal.data["level"]) - useTC = 2 - //Let's make this barely readable - if(signal.data["compression"] > 0) - t = Gibberish(t, signal.data["compression"] + 50) - - if(useMS && useTC) // only send the message if it's stable - if(useTC != 2) // Does our recipient have a broadcaster on their level? - U << "ERROR: Cannot reach recipient." - return - useMS.send_pda_message("[P.owner]","[owner]","[t]") - tnote.Add(list(list("sent" = 1, "owner" = "[P.owner]", "job" = "[P.ownjob]", "message" = "[t]", "target" = "\ref[P]"))) - P.tnote.Add(list(list("sent" = 0, "owner" = "[owner]", "job" = "[ownjob]", "message" = "[t]", "target" = "\ref[src]"))) -/* for(var/mob/M in player_list) - if(M.stat == DEAD && M.client && (M.client.prefs.toggles & CHAT_GHOSTEARS)) // src.client is so that ghosts don't have to listen to mice - if(istype(M, /mob/new_player)) - continue - M.show_message("PDA Message - [owner] -> [P.owner]: [t]") */ - investigate_log("PDA Message - [U.key] - [owner] -> [P.owner]: [t]", "pda") - if(!conversations.Find("\ref[P]")) - conversations.Add("\ref[P]") - if(!P.conversations.Find("\ref[src]")) - P.conversations.Add("\ref[src]") - -/* - if (prob(15)) //Give the AI a chance of intercepting the message - var/who = src.owner - if(prob(50)) - who = P.owner - for(var/mob/living/silicon/ai/ai in mob_list) - // Allows other AIs to intercept the message but the AI won't intercept their own message. - if(ai.aiPDA != P && ai.aiPDA != src) - ai.show_message("Intercepted message from [who]: [t]") -*/ - - P.play_ringtone() - //Search for holder of the PDA. - var/mob/living/L = null - if(P.loc && isliving(P.loc)) - L = P.loc - //Maybe they are a pAI! - else - L = get(P, /mob/living/silicon) - - - if(L) - L << "\icon[P] Message from [src.owner] ([ownjob]), \"[t]\" (Reply)" - nanomanager.update_user_uis(L, P) // Update the receiving user's PDA UI so that they can see the new message - - nanomanager.update_user_uis(U, P) // Update the sending user's PDA UI so that they can see the new message - - log_pda("[usr] (PDA: [src.name]) sent \"[t]\" to [P.name]") - P.overlays.Cut() - P.overlays += image('icons/obj/pda.dmi', "pda-r") - P.newmessage = 1 - else - U << "ERROR: Messaging server is not responding." - -/obj/item/device/pda/proc/play_ringtone() - if (!silent) - var/sound/S = sound('sound/machines/twobeep.ogg') - - if(ttone in ttone_sound) - S = ttone_sound[ttone] - playsound(loc, S, 50, 1) - for (var/mob/O in hearers(3, loc)) - if(!silent) O.show_message(text("\icon[src] *[ttone]*")) - -/obj/item/device/pda/verb/verb_remove_id() - set category = "Object" - set name = "Remove id" - set src in usr - - if(issilicon(usr)) - return - - if ( can_use(usr) ) - if(id) - remove_id() - else - usr << "This PDA does not have an ID in it." - else - usr << "You cannot do this while restrained." - - -/obj/item/device/pda/verb/verb_remove_pen() - set category = "Object" - set name = "Remove pen" - set src in usr - - if(issilicon(usr)) - return - - if ( can_use(usr) ) - var/obj/item/weapon/pen/O = locate() in src - if(O) - if (istype(loc, /mob)) - var/mob/M = loc - if(M.get_active_hand() == null) - M.put_in_hands(O) - usr << "You remove \the [O] from \the [src]." - return - O.loc = get_turf(src) - else - usr << "This PDA does not have a pen in it." - else - usr << "You cannot do this while restrained." - - -/obj/item/device/pda/proc/id_check(mob/user as mob, choice as num)//To check for IDs; 1 for in-pda use, 2 for out of pda use. - if(choice == 1) - if (id) - remove_id() - else - var/obj/item/I = user.get_active_hand() - if (istype(I, /obj/item/weapon/card/id)) - user.drop_item() - I.loc = src - id = I - else - var/obj/item/weapon/card/I = user.get_active_hand() - if (istype(I, /obj/item/weapon/card/id) && I:registered_name) - var/obj/old_id = id - user.drop_item() - I.loc = src - id = I - user.put_in_hands(old_id) - return - -// access to status display signals -/obj/item/device/pda/attackby(obj/item/C as obj, mob/user as mob, params) - ..() - if(istype(C, /obj/item/weapon/cartridge) && !cartridge) - cartridge = C - user.drop_item() - cartridge.loc = src - user << "You insert [cartridge] into [src]." - nanomanager.update_uis(src) // update all UIs attached to src - if(cartridge.radio) - cartridge.radio.hostpda = src - - else if(istype(C, /obj/item/weapon/card/id)) - var/obj/item/weapon/card/id/idcard = C - if(!idcard.registered_name) - user << "\The [src] rejects the ID." - return - if(!owner) - owner = idcard.registered_name - ownjob = idcard.assignment - ownrank = idcard.rank - name = "PDA-[owner] ([ownjob])" - user << "Card scanned." - else - //Basic safety check. If either both objects are held by user or PDA is on ground and card is in hand. - if(((src in user.contents) && (C in user.contents)) || (istype(loc, /turf) && in_range(src, user) && (C in user.contents)) ) - if( can_use(user) )//If they can still act. - id_check(user, 2) - user << "You put the ID into \the [src]'s slot." - updateSelfDialog()//Update self dialog on success. - return //Return in case of failed check or when successful. - updateSelfDialog()//For the non-input related code. - else if(istype(C, /obj/item/device/paicard) && !src.pai) - user.drop_item() - C.loc = src - pai = C - user << "You slot \the [C] into [src]." - nanomanager.update_uis(src) // update all UIs attached to src - else if(istype(C, /obj/item/weapon/pen)) - var/obj/item/weapon/pen/O = locate() in src - if(O) - user << "There is already a pen in \the [src]." - else - user.drop_item() - C.loc = src - user << "You slide \the [C] into \the [src]." - return - -/obj/item/device/pda/attack(mob/living/C as mob, mob/living/user as mob) - if (istype(C, /mob/living/carbon)) - switch(scanmode) - if(1) - for (var/mob/O in viewers(C, null)) - O.show_message("\red [user] has analyzed [C]'s vitals!", 1) - - user.show_message("\blue Analyzing Results for [C]:") - user.show_message("\blue \t Overall Status: [C.stat > 1 ? "dead" : "[C.health - C.halloss]% healthy"]", 1) - user.show_message("\blue \t Damage Specifics: [C.getOxyLoss() > 50 ? "\red" : "\blue"][C.getOxyLoss()]-[C.getToxLoss() > 50 ? "\red" : "\blue"][C.getToxLoss()]-[C.getFireLoss() > 50 ? "\red" : "\blue"][C.getFireLoss()]-[C.getBruteLoss() > 50 ? "\red" : "\blue"][C.getBruteLoss()]", 1) - user.show_message("\blue \t Key: Suffocation/Toxin/Burns/Brute", 1) - user.show_message("\blue \t Body Temperature: [C.bodytemperature-T0C]°C ([C.bodytemperature*1.8-459.67]°F)", 1) - if(C.timeofdeath && (C.stat == DEAD || (C.status_flags & FAKEDEATH))) - user.show_message("\blue \t Time of Death: [C.timeofdeath]") - if(istype(C, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = C - var/list/damaged = H.get_damaged_organs(1,1) - user.show_message("\blue Localized Damage, Brute/Burn:",1) - if(length(damaged)>0) - for(var/obj/item/organ/external/org in damaged) - user.show_message(text("\blue \t []: []\blue-[]",capitalize(org.name),(org.brute_dam > 0)?"\red [org.brute_dam]":0,(org.burn_dam > 0)?"\red [org.burn_dam]":0),1) - else - user.show_message("\blue \t Limbs are OK.",1) - - if(2) - if (!istype(C:dna, /datum/dna)) - user << "\blue No fingerprints found on [C]" - else - user << text("\blue [C]'s Fingerprints: [md5(C:dna.uni_identity)]") - if ( !(C:blood_DNA) ) - user << "\blue No blood found on [C]" - if(C:blood_DNA) - qdel(C:blood_DNA) - else - user << "\blue Blood found on [C]. Analysing..." - spawn(15) - for(var/blood in C:blood_DNA) - user << "\blue Blood type: [C:blood_DNA[blood]]\nDNA: [blood]" - - if(4) - for (var/mob/O in viewers(C, null)) - O.show_message("\red [user] has analyzed [C]'s radiation levels!", 1) - - user.show_message("\blue Analyzing Results for [C]:") - if(C.radiation) - user.show_message("\green Radiation Level: \black [C.radiation]") - else - user.show_message("\blue No radiation detected.") - -/obj/item/device/pda/afterattack(atom/A as mob|obj|turf|area, mob/user as mob, proximity) - if(!proximity) return - switch(scanmode) - - if(3) - if(!isnull(A.reagents)) - if(A.reagents.reagent_list.len > 0) - var/reagents_length = A.reagents.reagent_list.len - user << "[reagents_length] chemical agent[reagents_length > 1 ? "s" : ""] found." - for (var/re in A.reagents.reagent_list) - user << "\t [re]" - else - user << "No active chemical agents found in [A]." - else - user << "No significant chemical agents found in [A]." - - if(5) - if (istype(A, /obj/item/weapon/tank)) - var/obj/item/weapon/tank/T = A - atmosanalyzer_scan(T.air_contents, user, T) - else if (istype(A, /obj/machinery/portable_atmospherics)) - var/obj/machinery/portable_atmospherics/T = A - atmosanalyzer_scan(T.air_contents, user, T) - else if (istype(A, /obj/machinery/atmospherics/pipe)) - var/obj/machinery/atmospherics/pipe/T = A - atmosanalyzer_scan(T.parent.air, user, T) - else if (istype(A, /obj/machinery/power/rad_collector)) - var/obj/machinery/power/rad_collector/T = A - if(T.P) atmosanalyzer_scan(T.P.air_contents, user, T) - else if (istype(A, /obj/item/weapon/flamethrower)) - var/obj/item/weapon/flamethrower/T = A - if(T.ptank) atmosanalyzer_scan(T.ptank.air_contents, user, T) - else if (istype(A, /obj/machinery/portable_atmospherics/scrubber/huge)) - var/obj/machinery/portable_atmospherics/scrubber/huge/T = A - atmosanalyzer_scan(T.air_contents, user, T) - else if (istype(A, /obj/machinery/atmospherics/unary/tank)) - var/obj/machinery/atmospherics/unary/tank/T = A - atmosanalyzer_scan(T.air_contents, user, T) - - if (!scanmode && istype(A, /obj/item/weapon/paper) && owner) - // JMO 20140705: Makes scanned document show up properly in the notes. Not pretty for formatted documents, - // as this will clobber the HTML, but at least it lets you scan a document. You can restore the original - // notes by editing the note again. (Was going to allow you to edit, but scanned documents are too long.) - var/raw_scan = (A:info) - var/formatted_scan = "" - // Scrub out the tags (replacing a few formatting ones along the way) - // Find the beginning and end of the first tag. - var/tag_start = findtext(raw_scan,"<") - var/tag_stop = findtext(raw_scan,">") - // Until we run out of complete tags... - while(tag_start&&tag_stop) - var/pre = copytext(raw_scan,1,tag_start) // Get the stuff that comes before the tag - var/tag = lowertext(copytext(raw_scan,tag_start+1,tag_stop)) // Get the tag so we can do intellegent replacement - var/tagend = findtext(tag," ") // Find the first space in the tag if there is one. - // Anything that's before the tag can just be added as is. - formatted_scan = formatted_scan+pre - // If we have a space after the tag (and presumably attributes) just crop that off. - if (tagend) - tag=copytext(tag,1,tagend) - if (tag=="p"||tag=="/p"||tag=="br") // Check if it's I vertical space tag. - formatted_scan=formatted_scan+"
" // If so, add some padding in. - raw_scan = copytext(raw_scan,tag_stop+1) // continue on with the stuff after the tag - // Look for the next tag in what's left - tag_start = findtext(raw_scan,"<") - tag_stop = findtext(raw_scan,">") - // Anything that is left in the page. just tack it on to the end as is - formatted_scan=formatted_scan+raw_scan - // If there is something in there already, pad it out. - if (length(note)>0) - note = note + "

" - // Store the scanned document to the notes - note = "Scanned Document. Edit to restore previous notes/delete scan.
----------
" + formatted_scan + "
" - // notehtml ISN'T set to allow user to get their old notes back. A better implementation would add a "scanned documents" - // feature to the PDA, which would better convey the availability of the feature, but this will work for now. - // Inform the user - user << "\blue Paper scanned and OCRed to notekeeper." //concept of scanning paper copyright brainoblivion 2009 - -/obj/item/device/pda/proc/explode() //This needs tuning. - if(!src.detonate) return - var/turf/T = get_turf(src.loc) - - if (ismob(loc)) - var/mob/M = loc - M.show_message("Your [src] explodes!", 1) - - if(T) - T.hotspot_expose(700,125) - - explosion(T, -1, -1, 2, 3) - qdel(src) - return - -/obj/item/device/pda/Destroy() - PDAs -= src - if (src.id) - src.id.loc = get_turf(src.loc) - if(src.pai) - src.pai.loc = get_turf(src.loc) - return ..() - -/obj/item/device/pda/clown/Crossed(AM as mob|obj) //Clown PDA is slippery. - if (istype(AM, /mob/living/carbon)) - var/mob/living/carbon/M = AM - M.slip("pda", 8, 5, 0, 1) - -/obj/item/device/pda/proc/available_pdas() - var/list/names = list() - var/list/plist = list() - var/list/namecounts = list() - - if (toff) - usr << "Turn on your receiver in order to send messages." - return - - for (var/obj/item/device/pda/P in PDAs) - if (!P.owner) - continue - else if(P.hidden) - continue - else if (P == src) - continue - else if (P.toff) - continue - - var/name = P.owner - if (name in names) - namecounts[name]++ - name = text("[name] ([namecounts[name]])") - else - names.Add(name) - namecounts[name] = 1 - - plist[text("[name]")] = P - return plist - -//Some spare PDAs in a box -/obj/item/weapon/storage/box/PDAs - name = "spare PDAs" - desc = "A box of spare PDA microcomputers." - icon = 'icons/obj/pda.dmi' - icon_state = "pdabox" - - New() - ..() - new /obj/item/device/pda(src) - new /obj/item/device/pda(src) - new /obj/item/device/pda(src) - new /obj/item/device/pda(src) - new /obj/item/weapon/cartridge/head(src) - - var/newcart = pick( /obj/item/weapon/cartridge/engineering, - /obj/item/weapon/cartridge/security, - /obj/item/weapon/cartridge/medical, - /obj/item/weapon/cartridge/signal/toxins, - /obj/item/weapon/cartridge/quartermaster) - new newcart(src) - -// Pass along the pulse to atoms in contents, largely added so pAIs are vulnerable to EMP -/obj/item/device/pda/emp_act(severity) - for(var/atom/A in src) - A.emp_act(severity) diff --git a/code/game/objects/items/devices/PDA/cart.dm b/code/game/objects/items/devices/PDA/cart.dm deleted file mode 100644 index 2f5790c5fbb..00000000000 --- a/code/game/objects/items/devices/PDA/cart.dm +++ /dev/null @@ -1,612 +0,0 @@ -/obj/item/weapon/cartridge - name = "generic cartridge" - desc = "A data cartridge for portable microcomputers." - icon = 'icons/obj/pda.dmi' - icon_state = "cart" - item_state = "electronic" - w_class = 1 - - var/obj/item/radio/integrated/radio = null - var/access_security = 0 - var/access_engine = 0 - var/access_atmos = 0 - var/access_medical = 0 - var/access_clown = 0 - var/access_mime = 0 - var/access_janitor = 0 -// var/access_flora = 0 - var/access_reagent_scanner = 0 - var/access_remote_door = 0 // Control some blast doors remotely!! - var/remote_door_id = "" - var/access_status_display = 0 - var/access_quartermaster = 0 - var/access_detonate_pda = 0 - var/access_hydroponics = 0 - var/charges = 0 - var/mode = null - var/menu - var/datum/data/record/active1 = null //General - var/datum/data/record/active2 = null //Medical - var/datum/data/record/active3 = null //Security - var/obj/machinery/computer/monitor/powmonitor = null // Power Monitor - var/list/powermonitors = list() - var/message1 // used for status_displays - var/message2 - var/list/stored_data = list() - -/obj/item/weapon/cartridge/engineering - name = "Power-ON Cartridge" - icon_state = "cart-e" - access_engine = 1 - -/obj/item/weapon/cartridge/atmos - name = "BreatheDeep Cartridge" - icon_state = "cart-a" - access_atmos = 1 - -/obj/item/weapon/cartridge/medical - name = "Med-U Cartridge" - icon_state = "cart-m" - access_medical = 1 - -/obj/item/weapon/cartridge/chemistry - name = "ChemWhiz Cartridge" - icon_state = "cart-chem" - access_reagent_scanner = 1 - -/obj/item/weapon/cartridge/security - name = "R.O.B.U.S.T. Cartridge" - icon_state = "cart-s" - access_security = 1 - -/obj/item/weapon/cartridge/security/initialize() - radio = new /obj/item/radio/integrated/beepsky(src) - ..() - -/obj/item/weapon/cartridge/detective - name = "D.E.T.E.C.T. Cartridge" - icon_state = "cart-s" - access_security = 1 - access_medical = 1 - - -/obj/item/weapon/cartridge/janitor - name = "CustodiPRO Cartridge" - desc = "The ultimate in clean-room design." - icon_state = "cart-j" - access_janitor = 1 - -/obj/item/weapon/cartridge/lawyer - name = "P.R.O.V.E. Cartridge" - icon_state = "cart-s" - access_security = 1 - -/obj/item/weapon/cartridge/clown - name = "Honkworks 5.0" - icon_state = "cart-clown" - access_clown = 1 - charges = 5 - -/obj/item/weapon/cartridge/mime - name = "Gestur-O 1000" - icon_state = "cart-mi" - access_mime = 1 - charges = 5 -/* -/obj/item/weapon/cartridge/botanist - name = "Green Thumb v4.20" - icon_state = "cart-b" - access_flora = 1 -*/ - -/obj/item/weapon/cartridge/signal - name = "generic signaler cartridge" - desc = "A data cartridge with an integrated radio signaler module." - -/obj/item/weapon/cartridge/signal/toxins - name = "Signal Ace 2" - desc = "Complete with integrated radio signaler!" - icon_state = "cart-tox" - access_reagent_scanner = 1 - access_atmos = 1 - -/obj/item/weapon/cartridge/signal/initialize() - radio = new /obj/item/radio/integrated/signal(src) - ..() - -/obj/item/weapon/cartridge/signal/Destroy() - qdel(radio) - return ..() - -/obj/item/weapon/cartridge/quartermaster - name = "Space Parts & Space Vendors Cartridge" - desc = "Perfect for the Quartermaster on the go!" - icon_state = "cart-q" - access_quartermaster = 1 - -/obj/item/weapon/cartridge/quartermaster/initialize() - radio = new /obj/item/radio/integrated/mule(src) - ..() - -/obj/item/weapon/cartridge/head - name = "Easy-Record DELUXE" - icon_state = "cart-h" - access_status_display = 1 - -/obj/item/weapon/cartridge/hop - name = "HumanResources9001" - icon_state = "cart-h" - access_status_display = 1 - access_quartermaster = 1 - access_janitor = 1 - access_security = 1 - -/obj/item/weapon/cartridge/hop/initialize() - radio = new /obj/item/radio/integrated/mule(src) - ..() - -/obj/item/weapon/cartridge/hos - name = "R.O.B.U.S.T. DELUXE" - icon_state = "cart-hos" - access_status_display = 1 - access_security = 1 - -/obj/item/weapon/cartridge/hos/initialize() - radio = new /obj/item/radio/integrated/beepsky(src) - ..() - -/obj/item/weapon/cartridge/ce - name = "Power-On DELUXE" - icon_state = "cart-ce" - access_status_display = 1 - access_engine = 1 - access_atmos = 1 - -/obj/item/weapon/cartridge/cmo - name = "Med-U DELUXE" - icon_state = "cart-cmo" - access_status_display = 1 - access_reagent_scanner = 1 - access_medical = 1 - -/obj/item/weapon/cartridge/rd - name = "Signal Ace DELUXE" - icon_state = "cart-rd" - access_status_display = 1 - access_reagent_scanner = 1 - access_atmos = 1 - -/obj/item/weapon/cartridge/rd/initialize() - radio = new /obj/item/radio/integrated/signal(src) - ..() - -/obj/item/weapon/cartridge/captain - name = "Value-PAK Cartridge" - desc = "Now with 200% more value!" - icon_state = "cart-c" - access_quartermaster = 1 - access_janitor = 1 - access_engine = 1 - access_security = 1 - access_medical = 1 - access_reagent_scanner = 1 - access_status_display = 1 - access_atmos = 1 - -/obj/item/weapon/cartridge/captain/initialize() - radio = new /obj/item/radio/integrated/beepsky(src) - ..() - -/obj/item/weapon/cartridge/supervisor - name = "Easy-Record DELUXE" - icon_state = "cart-h" - access_status_display = 1 - access_security = 1 - -/obj/item/weapon/cartridge/centcom - name = "Value-PAK Cartridge" - desc = "Now with 200% more value!" - icon_state = "cart-c" - access_quartermaster = 1 - access_janitor = 1 - access_engine = 1 - access_security = 1 - access_medical = 1 - access_reagent_scanner = 1 - access_status_display = 1 - access_atmos = 1 - -/obj/item/weapon/cartridge/centcom/initialize() - radio = new /obj/item/radio/integrated/beepsky(src) - ..() - -/obj/item/weapon/cartridge/syndicate - name = "Detomatix Cartridge" - icon_state = "cart" - access_remote_door = 1 - access_detonate_pda = 1 - remote_door_id = "smindicate" //Make sure this matches the syndicate shuttle's shield/door id!! //don't ask about the name, testing. - charges = 4 - -/obj/item/weapon/cartridge/proc/post_status(var/command, var/data1, var/data2) - - var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435) - if(!frequency) return - - var/datum/signal/status_signal = new - status_signal.source = src - status_signal.transmission_method = 1 - status_signal.data["command"] = command - - switch(command) - if("message") - status_signal.data["msg1"] = data1 - status_signal.data["msg2"] = data2 - if(loc) - var/obj/item/PDA = loc - var/mob/user = PDA.fingerprintslast - if(istype(PDA.loc,/mob/living)) - name = PDA.loc - log_admin("STATUS: [user] set status screen with [PDA]. Message: [data1] [data2]") - message_admins("STATUS: [user] set status screen with [PDA]. Message: [data1] [data2]") - - if("alert") - status_signal.data["picture_state"] = data1 - - frequency.post_signal(src, status_signal) - - -/* - This generates the nano values of the cart menus. - Because we close the UI when we insert a new cart - we don't have to worry about null values on items - the user can't access. Well, unless they are href hacking. - But in that case their UI will just lock up. -*/ - - -/obj/item/weapon/cartridge/proc/create_NanoUI_values(mob/user as mob) - var/values[0] - - /* Signaler (Mode: 40) */ - - - if(istype(radio,/obj/item/radio/integrated/signal) && (mode==40)) - var/obj/item/radio/integrated/signal/R = radio - values["signal_freq"] = format_frequency(R.frequency) - values["signal_code"] = R.code - - - /* Station Display (Mode: 42) */ - - if(mode==42) - values["message1"] = message1 ? message1 : "(none)" - values["message2"] = message2 ? message2 : "(none)" - - - - /* Power Monitor (Mode: 43 / 433) */ - if(mode==43 || mode==433) - values["powermonitors"] = powermonitor_repository.powermonitor_data() - - if (powmonitor && !isnull(powmonitor.powernet)) - values["powerconnected"] = 1 - values["poweravail"] = powmonitor.powernet.avail - values["powerload"] = num2text(powmonitor.powernet.viewload,10) - values["powerdemand"] = powmonitor.powernet.load - values["apcs"] = apc_repository.apc_data(powmonitor) - else - values["powerconnected"] = 0 - - - - - - /* General Records (Mode: 44 / 441 / 45 / 451) */ - if(mode == 44 || mode == 441 || mode == 45 || mode ==451) - if(istype(active1, /datum/data/record) && (active1 in data_core.general)) - values["general"] = active1.fields - values["general_exists"] = 1 - - else - - values["general_exists"] = 0 - - - - /* Medical Records (Mode: 44 / 441) */ - - if(mode == 44 || mode == 441) - var/medData[0] - for(var/datum/data/record/R in sortRecord(data_core.general)) - medData[++medData.len] = list(Name = R.fields["name"],"ref" = "\ref[R]") - values["medical_records"] = medData - - if(istype(active2, /datum/data/record) && (active2 in data_core.medical)) - values["medical"] = active2.fields - values["medical_exists"] = 1 - else - values["medical_exists"] = 0 - - /* Security Records (Mode:45 / 451) */ - - if(mode == 45 || mode == 451) - var/secData[0] - for (var/datum/data/record/R in sortRecord(data_core.general)) - secData[++secData.len] = list(Name = R.fields["name"], "ref" = "\ref[R]") - values["security_records"] = secData - - if(istype(active3, /datum/data/record) && (active3 in data_core.security)) - values["security"] = active3.fields - values["security_exists"] = 1 - else - values["security_exists"] = 0 - - /* Security Bot Control (Mode: 46) */ - - if(mode==46) - var/botsData[0] - var/beepskyData[0] - if(istype(radio,/obj/item/radio/integrated/beepsky)) - var/obj/item/radio/integrated/beepsky/SC = radio - beepskyData["active"] = SC.active - if(SC.active && !isnull(SC.botstatus)) - var/area/loca = SC.botstatus["loca"] - var/loca_name = sanitize(loca.name) - beepskyData["botstatus"] = list("loca" = loca_name, "mode" = SC.botstatus["mode"]) - else - beepskyData["botstatus"] = list("loca" = null, "mode" = -1) - var/botsCount=0 - if(SC.botlist && SC.botlist.len) - for(var/obj/machinery/bot/B in SC.botlist) - botsCount++ - if(B.loc) - botsData[++botsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "ref" = "\ref[B]") - - if(!botsData.len) - botsData[++botsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) - - beepskyData["bots"] = botsData - beepskyData["count"] = botsCount - - else - beepskyData["active"] = 0 - botsData[++botsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) - beepskyData["botstatus"] = list("loca" = null, "mode" = null) - beepskyData["bots"] = botsData - beepskyData["count"] = 0 - - values["beepsky"] = beepskyData - - - /* MULEBOT Control (Mode: 48) */ - - if(mode==48) - var/muleData[0] - var/mulebotsData[0] - if(istype(radio,/obj/item/radio/integrated/mule)) - var/obj/item/radio/integrated/mule/QC = radio - muleData["active"] = QC.active - if(QC.active && !isnull(QC.botstatus)) - var/area/loca = QC.botstatus["loca"] - var/loca_name = sanitize(loca.name) - muleData["botstatus"] = list("loca" = loca_name, "mode" = QC.botstatus["mode"],"home"=QC.botstatus["home"],"powr" = QC.botstatus["powr"],"retn" =QC.botstatus["retn"], "pick"=QC.botstatus["pick"], "load" = QC.botstatus["load"], "dest" = sanitize(QC.botstatus["dest"])) - - else - muleData["botstatus"] = list("loca" = null, "mode" = -1,"home"=null,"powr" = null,"retn" =null, "pick"=null, "load" = null, "dest" = null) - - - var/mulebotsCount=0 - for(var/obj/machinery/bot/B in QC.botlist) - mulebotsCount++ - if(B.loc) - mulebotsData[++mulebotsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "ref" = "\ref[B]") - - if(!mulebotsData.len) - mulebotsData[++mulebotsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) - - muleData["bots"] = mulebotsData - muleData["count"] = mulebotsCount - - else - muleData["botstatus"] = list("loca" = null, "mode" = -1,"home"=null,"powr" = null,"retn" =null, "pick"=null, "load" = null, "dest" = null) - muleData["active"] = 0 - mulebotsData[++mulebotsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) - muleData["bots"] = mulebotsData - muleData["count"] = 0 - - values["mulebot"] = muleData - - - - /* Supply Shuttle Requests Menu (Mode: 47) */ - - if(mode==47) - var/supplyData[0] - - if(shuttle_master.supply.mode == SHUTTLE_CALL) - supplyData["shuttle_moving"] = 1 - - if(shuttle_master.supply.z != ZLEVEL_STATION) - supplyData["shuttle_loc"] = "station" - else - supplyData["shuttle_loc"] = "centcom" - - supplyData["shuttle_time"] = "([shuttle_master.supply.timeLeft(600)] Mins)" - - var/supplyOrderCount = 0 - var/supplyOrderData[0] - for(var/S in shuttle_master.shoppinglist) - var/datum/supply_order/SO = S - supplyOrderData[++supplyOrderData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "ApprovedBy" = SO.orderedby, "Comment" = html_encode(SO.comment)) - - if(!supplyOrderData.len) - supplyOrderData[++supplyOrderData.len] = list("Number" = null, "Name" = null, "OrderedBy"=null) - - supplyData["approved"] = supplyOrderData - supplyData["approved_count"] = supplyOrderCount - - var/requestCount = 0 - var/requestData[0] - for(var/S in shuttle_master.requestlist) - var/datum/supply_order/SO = S - requestCount++ - requestData[++requestData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "OrderedBy" = SO.orderedby, "Comment" = html_encode(SO.comment)) - - if(!requestData.len) - requestData[++requestData.len] = list("Number" = null, "Name" = null, "orderedBy" = null, "Comment" = null) - - supplyData["requests"] = requestData - supplyData["requests_count"] = requestCount - - - values["supply"] = supplyData - - - - /* Janitor Supplies Locator (Mode: 49) */ - if(mode==49) - var/JaniData[0] - var/turf/cl = get_turf(src) - - if(cl) - JaniData["user_loc"] = list("x" = cl.x, "y" = cl.y) - else - JaniData["user_loc"] = list("x" = 0, "y" = 0) - var/MopData[0] - for(var/obj/item/weapon/mop/M in janitorial_equipment) - var/turf/ml = get_turf(M) - if(ml) - if(ml.z != cl.z) - continue - var/direction = get_dir(src, M) - MopData[++MopData.len] = list ("x" = ml.x, "y" = ml.y, "dir" = uppertext(dir2text(direction)), "status" = M.reagents.total_volume ? "Wet" : "Dry") - - if(!MopData.len) - MopData[++MopData.len] = list("x" = 0, "y" = 0, dir=null, status = null) - - - var/BucketData[0] - for(var/obj/structure/mopbucket/B in janitorial_equipment) - var/turf/bl = get_turf(B) - if(bl) - if(bl.z != cl.z) - continue - var/direction = get_dir(src,B) - BucketData[++BucketData.len] = list ("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.reagents.total_volume/100) - - if(!BucketData.len) - BucketData[++BucketData.len] = list("x" = 0, "y" = 0, dir=null, status = null) - - var/CbotData[0] - for(var/obj/machinery/bot/cleanbot/B in aibots) - var/turf/bl = get_turf(B) - if(bl) - if(bl.z != cl.z) - continue - var/direction = get_dir(src,B) - CbotData[++CbotData.len] = list("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.on ? "Online" : "Offline") - - - if(!CbotData.len) - CbotData[++CbotData.len] = list("x" = 0, "y" = 0, dir=null, status = null) - var/CartData[0] - for(var/obj/structure/janitorialcart/B in janitorial_equipment) - var/turf/bl = get_turf(B) - if(bl) - if(bl.z != cl.z) - continue - var/direction = get_dir(src,B) - CartData[++CartData.len] = list("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.reagents.total_volume/100) - if(!CartData.len) - CartData[++CartData.len] = list("x" = 0, "y" = 0, dir=null, status = null) - - - - - JaniData["mops"] = MopData - JaniData["buckets"] = BucketData - JaniData["cleanbots"] = CbotData - JaniData["carts"] = CartData - values["janitor"] = JaniData - - return values - - - - - -/obj/item/weapon/cartridge/Topic(href, href_list) - ..() - - if (!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) - usr.unset_machine() - usr << browse(null, "window=pda") - return - - - - - switch(href_list["choice"]) - if("Medical Records") - var/datum/data/record/R = locate(href_list["target"]) - var/datum/data/record/M = locate(href_list["target"]) - loc:mode = 441 - mode = 441 - if (R in data_core.general) - for (var/datum/data/record/E in data_core.medical) - if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) - M = E - break - active1 = R - active2 = M - - if("Security Records") - var/datum/data/record/R = locate(href_list["target"]) - var/datum/data/record/S = locate(href_list["target"]) - loc:mode = 451 - mode = 451 - if (R in data_core.general) - for (var/datum/data/record/E in data_core.security) - if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) - S = E - break - active1 = R - active3 = S - - if("Send Signal") - spawn( 0 ) - radio:send_signal("ACTIVATE") - return - - if("Signal Frequency") - var/new_frequency = sanitize_frequency(radio:frequency + text2num(href_list["sfreq"])) - radio:set_frequency(new_frequency) - - if("Signal Code") - radio:code += text2num(href_list["scode"]) - radio:code = round(radio:code) - radio:code = min(100, radio:code) - radio:code = max(1, radio:code) - - if("Status") - switch(href_list["statdisp"]) - if("message") - post_status("message", message1, message2) - if("alert") - post_status("alert", href_list["alert"]) - if("setmsg1") - message1 = input("Line 1", "Enter Message Text", message1) as text|null - updateSelfDialog() - if("setmsg2") - message2 = input("Line 2", "Enter Message Text", message2) as text|null - updateSelfDialog() - else - post_status(href_list["statdisp"]) - if("Power Select") - var/pref = href_list["target"] - powmonitor = locate(pref) - loc:mode = 433 - mode = 433 - - return 1 diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm index 4412bff1265..75432a86da2 100644 --- a/code/game/objects/items/stacks/rods.dm +++ b/code/game/objects/items/stacks/rods.dm @@ -36,17 +36,22 @@ return if(WT.remove_fuel(0,user)) - var/obj/item/stack/sheet/metal/new_item = new(usr.loc) - new_item.add_to_stacks(usr) + var/obj/item/stack/sheet/metal/new_item = new(user.loc) + new_item.add_to_stacks(user) + if(new_item.get_amount() <= 0) + // stack was moved into another one on the pile + new_item = locate() in user.loc + user.visible_message("[user.name] shaped [src] into metal with the weldingtool.", \ "You shaped [src] into metal with the weldingtool.", \ "You hear welding.") - var/obj/item/stack/rods/R = src - src = null - var/replace = (user.get_inactive_hand()==R) - R.use(2) - if (!R && replace) - user.put_in_hands(new_item) + + var/replace = user.get_inactive_hand() == src + use(2) + if (get_amount() <= 0 && replace) + user.unEquip(src, 1) + if(new_item) + user.put_in_hands(new_item) return ..() diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 6a3493fc0ea..45d15625e06 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -51,9 +51,9 @@ if(!proximity) return if (istype(A, /obj/structure/reagent_dispensers/watertank) && get_dist(src,A) <= 1) A.reagents.trans_to(src, 10) - user << "\blue You fill the balloon with the contents of [A]." - src.desc = "A translucent balloon with some form of liquid sloshing around in it." - src.update_icon() + user << "You fill the balloon with the contents of [A]." + desc = "A translucent balloon with some form of liquid sloshing around in it." + update_icon() return /obj/item/toy/balloon/attackby(obj/O as obj, mob/user as mob, params) @@ -67,19 +67,19 @@ O.reagents.reaction(user) qdel(src) else - src.desc = "A translucent balloon with some form of liquid sloshing around in it." - user << "\blue You fill the balloon with the contents of [O]." + desc = "A translucent balloon with some form of liquid sloshing around in it." + user << "You fill the balloon with the contents of [O]." O.reagents.trans_to(src, 10) - src.update_icon() + update_icon() return /obj/item/toy/balloon/throw_impact(atom/hit_atom) - if(src.reagents.total_volume >= 1) - src.visible_message("\red The [src] bursts!","You hear a pop and a splash.") - src.reagents.reaction(get_turf(hit_atom)) + if(reagents.total_volume >= 1) + visible_message("The [src] bursts!","You hear a pop and a splash.") + reagents.reaction(get_turf(hit_atom)) for(var/atom/A in get_turf(hit_atom)) - src.reagents.reaction(A) - src.icon_state = "burst" + reagents.reaction(A) + icon_state = "burst" spawn(5) if(src) qdel(src) @@ -141,89 +141,84 @@ attack_verb = list("attacked", "struck", "hit") var/bullets = 5 - examine(mob/user) - ..(user) - if (bullets) - user << "\blue It is loaded with [bullets] foam darts!" +/obj/item/toy/crossbow/examine(mob/user) + ..(user) + if (bullets) + user << "It is loaded with [bullets] foam darts!" - attackby(obj/item/I as obj, mob/user as mob, params) - if(istype(I, /obj/item/toy/ammo/crossbow)) - if(bullets <= 4) - user.drop_item() - qdel(I) - bullets++ - user << "\blue You load the foam dart into the crossbow." - else - usr << "\red It's already fully loaded." +/obj/item/toy/crossbow/attackby(obj/item/I as obj, mob/user as mob, params) + if(istype(I, /obj/item/toy/ammo/crossbow)) + if(bullets <= 4) + user.drop_item() + qdel(I) + bullets++ + user << "You load the foam dart into the crossbow." + else + usr << "It's already fully loaded." - afterattack(atom/target as mob|obj|turf|area, mob/user as mob, flag) - if(!isturf(target.loc) || target == user) return - if(flag) return +/obj/item/toy/crossbow/afterattack(atom/target as mob|obj|turf|area, mob/user as mob, flag) + if(!isturf(target.loc) || target == user) return + if(flag) return - if (locate (/obj/structure/table, src.loc)) - return - else if (bullets) - var/turf/trg = get_turf(target) - var/obj/effect/foam_dart_dummy/D = new/obj/effect/foam_dart_dummy(get_turf(src)) - bullets-- - D.icon_state = "foamdart" - D.name = "foam dart" - playsound(user.loc, 'sound/items/syringeproj.ogg', 50, 1) + if (locate (/obj/structure/table, src.loc)) + return + else if (bullets) + var/turf/trg = get_turf(target) + var/obj/effect/foam_dart_dummy/D = new/obj/effect/foam_dart_dummy(get_turf(src)) + bullets-- + D.icon_state = "foamdart" + D.name = "foam dart" + playsound(user.loc, 'sound/items/syringeproj.ogg', 50, 1) - for(var/i=0, i<6, i++) - if (D) - if(D.loc == trg) break - step_towards(D,trg) + for(var/i=0, i<6, i++) + if (D) + if(D.loc == trg) break + step_towards(D,trg) - for(var/mob/living/M in D.loc) - if(!istype(M,/mob/living)) continue - if(M == user) continue - D.visible_message("[M] was hit by the foam dart!") - new /obj/item/toy/ammo/crossbow(M.loc) - qdel(D) - return - - for(var/atom/A in D.loc) - if(A == user) continue - if(A.density) - new /obj/item/toy/ammo/crossbow(A.loc) - qdel(D) - - sleep(1) - - spawn(10) - if(D) - new /obj/item/toy/ammo/crossbow(D.loc) + for(var/mob/living/M in D.loc) + if(!istype(M,/mob/living)) continue + if(M == user) continue + D.visible_message("[M] was hit by the foam dart!") + new /obj/item/toy/ammo/crossbow(M.loc) qdel(D) + return - return - else if (bullets == 0) - user.Weaken(5) - user.visible_message("[] realized they were out of ammo and starting scrounging for some!") + for(var/atom/A in D.loc) + if(A == user) continue + if(A.density) + new /obj/item/toy/ammo/crossbow(A.loc) + qdel(D) + + sleep(1) + + spawn(10) + if(D) + new /obj/item/toy/ammo/crossbow(D.loc) + qdel(D) + + return + else if (bullets == 0) + user.Weaken(5) + user.visible_message("[] realized they were out of ammo and starting scrounging for some!") - attack(mob/M as mob, mob/user as mob) - src.add_fingerprint(user) +/obj/item/toy/crossbow/attack(mob/M as mob, mob/user as mob) + add_fingerprint(user) // ******* Check - if (src.bullets > 0 && M.lying) - - for(var/mob/O in viewers(M, null)) - if(O.client) - O.show_message(text("[] casually lines up a shot with []'s head and pulls the trigger!", user, M), 1, "You hear the sound of foam against skull.", 2) - O.show_message(text("\red [] was hit in the head by the foam dart!", M), 1) - - playsound(user.loc, 'sound/items/syringeproj.ogg', 50, 1) - new /obj/item/toy/ammo/crossbow(M.loc) - src.bullets-- - else if (M.lying && src.bullets == 0) - for(var/mob/O in viewers(M, null)) - if (O.client) O.show_message(text("[] casually lines up a shot with []'s head, pulls the trigger, then realizes they are out of ammo and drops to the floor in search of some!", user, M), 1, "You hear someone fall.", 2) - user.Weaken(5) - return + if (bullets > 0 && M.lying) + visible_message("[user] casually lines up a shot with [M]'s head and pulls the trigger!", "You hear the sound of foam against skull.") + M.visible_message("[M] was hit in the head by the foam dart!") + playsound(user.loc, 'sound/items/syringeproj.ogg', 50, 1) + new /obj/item/toy/ammo/crossbow(M.loc) + bullets-- + else if (M.lying && bullets == 0) + visible_message("[user] casually lines up a shot with [M]'s head, pulls the trigger, then realizes they are out of ammo and drops to the floor in search of some!", "You hear someone fall.") + user.Weaken(5) + return /obj/item/toy/ammo/crossbow name = "foam dart" @@ -279,27 +274,27 @@ flags = NOSHIELD attack_verb = list("attacked", "struck", "hit") - attack_self(mob/user as mob) - src.active = !( src.active ) - if (src.active) - user << "\blue You extend the plastic blade with a quick flick of your wrist." - playsound(user, 'sound/weapons/saberon.ogg', 50, 1) - src.icon_state = "swordblue" - src.item_state = "swordblue" - src.w_class = 4 - else - user << "\blue You push the plastic blade back down into the handle." - playsound(user, 'sound/weapons/saberoff.ogg', 50, 1) - src.icon_state = "sword0" - src.item_state = "sword0" - src.w_class = 2 +/obj/item/toy/sword/attack_self(mob/user as mob) + active = !(active) + if (active) + user << "You extend the plastic blade with a quick flick of your wrist." + playsound(user, 'sound/weapons/saberon.ogg', 50, 1) + icon_state = "swordblue" + item_state = "swordblue" + w_class = 4 + else + user << "You push the plastic blade back down into the handle." + playsound(user, 'sound/weapons/saberoff.ogg', 50, 1) + icon_state = "sword0" + item_state = "sword0" + w_class = 2 - if(istype(user,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = user - H.update_inv_l_hand() - H.update_inv_r_hand() - src.add_fingerprint(user) - return + if(istype(user,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + H.update_inv_l_hand() + H.update_inv_r_hand() + add_fingerprint(user) + return // Copied from /obj/item/weapon/melee/energy/sword/attackby /obj/item/toy/sword/attackby(obj/item/weapon/W, mob/living/user, params) @@ -374,21 +369,15 @@ w_class = 1 - throw_impact(atom/hit_atom) - ..() - var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() - new /obj/effect/decal/cleanable/ash(src.loc) - src.visible_message("\red The [src.name] explodes!","\red You hear a bang!") - - - playsound(src, 'sound/effects/snap.ogg', 50, 1) - qdel(src) - - - - +/obj/item/toy/snappop/virus/throw_impact(atom/hit_atom) + ..() + var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + new /obj/effect/decal/cleanable/ash(src.loc) + visible_message("The [name] explodes!","You hear a bang!") + playsound(src, 'sound/effects/snap.ogg', 50, 1) + qdel(src) /* * Snap pops @@ -400,27 +389,27 @@ icon_state = "snappop" w_class = 1 - throw_impact(atom/hit_atom) - ..() - var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() - new /obj/effect/decal/cleanable/ash(src.loc) - src.visible_message("\red The [src.name] explodes!","\red You hear a snap!") - playsound(src, 'sound/effects/snap.ogg', 50, 1) - qdel(src) +/obj/item/toy/snappop/throw_impact(atom/hit_atom) + ..() + var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + new /obj/effect/decal/cleanable/ash(src.loc) + visible_message("The [src.name] explodes!","You hear a snap!") + playsound(src, 'sound/effects/snap.ogg', 50, 1) + qdel(src) /obj/item/toy/snappop/Crossed(H as mob|obj) if((ishuman(H))) //i guess carp and shit shouldn't set them off var/mob/living/carbon/M = H if(M.m_intent == "run") - M << "\red You step on the snap pop!" + M << "You step on the snap pop!" var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread s.set_up(2, 0, src) s.start() new /obj/effect/decal/cleanable/ash(src.loc) - src.visible_message("\red The [src.name] explodes!","\red You hear a snap!") + visible_message("The [name] explodes!","You hear a snap!") playsound(src, 'sound/effects/snap.ogg', 50, 1) qdel(src) @@ -450,13 +439,13 @@ return ..() -/obj/random/prize +/obj/random/mech name = "Random Mech Prize" desc = "This is a random prize" icon = 'icons/obj/toy.dmi' icon_state = "ripleytoy" -/obj/random/prize/item_to_spawn() +/obj/random/mech/item_to_spawn() return pick(subtypesof(/obj/item/toy/prize)) //exclude the base type. /obj/item/toy/prize/ripley @@ -591,7 +580,7 @@ obj/item/toy/cards/deck/New() obj/item/toy/cards/deck/attack_hand(mob/user as mob) var/choice = null if(cards.len == 0) - src.icon_state = "deck_[deckstyle]_empty" + icon_state = "deck_[deckstyle]_empty" user << "There are no more cards to draw." return var/obj/item/toy/cards/singlecard/H = new/obj/item/toy/cards/singlecard(user.loc) @@ -600,16 +589,16 @@ obj/item/toy/cards/deck/attack_hand(mob/user as mob) H.parentdeck = src var/O = src H.apply_card_vars(H,O) - src.cards -= choice + cards -= choice H.pickup(user) user.put_in_active_hand(H) - src.visible_message("[user] draws a card from the deck.", "You draw a card from the deck.") + visible_message("[user] draws a card from the deck.", "You draw a card from the deck.") if(cards.len > 26) - src.icon_state = "deck_[deckstyle]_full" + icon_state = "deck_[deckstyle]_full" else if(cards.len > 10) - src.icon_state = "deck_[deckstyle]_half" + icon_state = "deck_[deckstyle]_half" else if(cards.len > 1) - src.icon_state = "deck_[deckstyle]_low" + icon_state = "deck_[deckstyle]_low" obj/item/toy/cards/deck/attack_self(mob/user as mob) if(cooldown < world.time - 50) @@ -625,17 +614,17 @@ obj/item/toy/cards/deck/attackby(obj/item/toy/cards/singlecard/C, mob/living/use if(!user.unEquip(C)) user << "The card is stuck to your hand, you can't add it to the deck!" return - src.cards += C.cardname + cards += C.cardname user.visible_message("[user] adds a card to the bottom of the deck.","You add the card to the bottom of the deck.") qdel(C) else user << "You can't mix cards from other decks." if(cards.len > 26) - src.icon_state = "deck_[deckstyle]_full" + icon_state = "deck_[deckstyle]_full" else if(cards.len > 10) - src.icon_state = "deck_[deckstyle]_half" + icon_state = "deck_[deckstyle]_half" else if(cards.len > 1) - src.icon_state = "deck_[deckstyle]_low" + icon_state = "deck_[deckstyle]_low" obj/item/toy/cards/deck/attackby(obj/item/toy/cards/cardhand/C, mob/living/user, params) @@ -645,17 +634,17 @@ obj/item/toy/cards/deck/attackby(obj/item/toy/cards/cardhand/C, mob/living/user, if(!user.unEquip(C)) user << "The hand of cards is stuck to your hand, you can't add it to the deck!" return - src.cards += C.currenthand + cards += C.currenthand user.visible_message("[user] puts their hand of cards in the deck.", "You put the hand of cards in the deck.") qdel(C) else user << "You can't mix cards from other decks." if(cards.len > 26) - src.icon_state = "deck_[deckstyle]_full" + icon_state = "deck_[deckstyle]_full" else if(cards.len > 10) - src.icon_state = "deck_[deckstyle]_half" + icon_state = "deck_[deckstyle]_half" else if(cards.len > 1) - src.icon_state = "deck_[deckstyle]_low" + icon_state = "deck_[deckstyle]_low" obj/item/toy/cards/deck/MouseDrop(atom/over_object) var/mob/M = usr @@ -718,7 +707,7 @@ obj/item/toy/cards/cardhand/Topic(href, href_list) if (cardUser.get_item_by_slot(slot_l_hand) == src || cardUser.get_item_by_slot(slot_r_hand) == src) var/choice = href_list["pick"] var/obj/item/toy/cards/singlecard/C = new/obj/item/toy/cards/singlecard(cardUser.loc) - src.currenthand -= choice + currenthand -= choice C.parentdeck = src.parentdeck C.cardname = choice C.apply_card_vars(C,O) @@ -727,13 +716,13 @@ obj/item/toy/cards/cardhand/Topic(href, href_list) cardUser.visible_message("[cardUser] draws a card from \his hand.", "You take the [C.cardname] from your hand.") interact(cardUser) - if(src.currenthand.len < 3) - src.icon_state = "[deckstyle]_hand2" + if(currenthand.len < 3) + icon_state = "[deckstyle]_hand2" else if(src.currenthand.len < 4) - src.icon_state = "[deckstyle]_hand3" + icon_state = "[deckstyle]_hand3" else if(src.currenthand.len < 5) - src.icon_state = "[deckstyle]_hand4" - if(src.currenthand.len == 1) + icon_state = "[deckstyle]_hand4" + if(currenthand.len == 1) var/obj/item/toy/cards/singlecard/N = new/obj/item/toy/cards/singlecard(src.loc) N.parentdeck = src.parentdeck N.cardname = src.currenthand[1] @@ -748,17 +737,17 @@ obj/item/toy/cards/cardhand/Topic(href, href_list) obj/item/toy/cards/cardhand/attackby(obj/item/toy/cards/singlecard/C, mob/living/user, params) if(istype(C)) - if(C.parentdeck == src.parentdeck) - src.currenthand += C.cardname + if(C.parentdeck == parentdeck) + currenthand += C.cardname user.unEquip(C) user.visible_message("[user] adds a card to their hand.", "You add the [C.cardname] to your hand.") interact(user) if(currenthand.len > 4) - src.icon_state = "[deckstyle]_hand5" + icon_state = "[deckstyle]_hand5" else if(currenthand.len > 3) - src.icon_state = "[deckstyle]_hand4" + icon_state = "[deckstyle]_hand4" else if(currenthand.len > 2) - src.icon_state = "[deckstyle]_hand3" + icon_state = "[deckstyle]_hand3" qdel(C) else user << "You can't mix cards from other decks." @@ -803,33 +792,33 @@ obj/item/toy/cards/singlecard/verb/Flip() if(usr.stat || !ishuman(usr) || !usr.canmove || usr.restrained()) return if(!flipped) - src.flipped = 1 + flipped = 1 if (cardname) - src.icon_state = "sc_[cardname]_[deckstyle]" - src.name = src.cardname + icon_state = "sc_[cardname]_[deckstyle]" + name = cardname else - src.icon_state = "sc_Ace of Spades_[deckstyle]" - src.name = "What Card" - src.pixel_x = 5 + icon_state = "sc_Ace of Spades_[deckstyle]" + name = "What Card" + pixel_x = 5 else if(flipped) - src.flipped = 0 - src.icon_state = "singlecard_down_[deckstyle]" - src.name = "card" - src.pixel_x = -5 + flipped = 0 + icon_state = "singlecard_down_[deckstyle]" + name = "card" + pixel_x = -5 obj/item/toy/cards/singlecard/attackby(obj/item/I, mob/living/user, params) if(istype(I, /obj/item/toy/cards/singlecard/)) var/obj/item/toy/cards/singlecard/C = I - if(C.parentdeck == src.parentdeck) + if(C.parentdeck == parentdeck) var/obj/item/toy/cards/cardhand/H = new/obj/item/toy/cards/cardhand(user.loc) H.currenthand += C.cardname - H.currenthand += src.cardname + H.currenthand += cardname H.parentdeck = C.parentdeck H.apply_card_vars(H,C) user.unEquip(C) H.pickup(user) user.put_in_active_hand(H) - user << "You combine the [C.cardname] and the [src.cardname] into a hand." + user << "You combine the [C.cardname] and the [cardname] into a hand." qdel(C) qdel(src) else @@ -923,54 +912,58 @@ obj/item/toy/cards/deck/syndicate/black var/timeleft = (cooldown - world.time) user << "Nothing happens, and '[round(timeleft/10)]' appears on a small display." - -/obj/item/toy/therapy_red - name = "red therapy doll" - desc = "A toy for therapeutic and recreational purposes. This one is red." - icon = 'icons/obj/weapons.dmi' +/obj/item/toy/therapy + name = "therapy doll" + desc = "A toy for therapeutic and recreational purposes." icon_state = "therapyred" + item_state = "egg4" + w_class = 1 + var/cooldown = 0 + +/obj/item/toy/therapy/New() + if(item_color) + name = "[item_color] therapy doll" + desc += " This one is [item_color]." + icon_state = "therapy[item_color]" + +/obj/item/toy/therapy/attack_self(mob/user) + if(cooldown < world.time - 8) + user << "You relieve some stress with \the [src]." + playsound(user, 'sound/items/squeaktoy.ogg', 20, 1) + cooldown = world.time + +/obj/random/therapy + name = "Random Therapy Doll" + desc = "This is a random therapy doll." + icon = 'icons/obj/toy.dmi' + icon_state = "therapyred" + +/obj/random/prize/item_to_spawn() + return pick(subtypesof(/obj/item/toy/therapy)) //exclude the base type. + +/obj/item/toy/therapy/red item_state = "egg4" // It's the red egg in items_left/righthand - w_class = 1 + item_color = "red" -/obj/item/toy/therapy_purple - name = "purple therapy doll" - desc = "A toy for therapeutic and recreational purposes. This one is purple." - icon = 'icons/obj/weapons.dmi' - icon_state = "therapypurple" +/obj/item/toy/therapy/purple item_state = "egg1" // It's the magenta egg in items_left/righthand - w_class = 1 + item_color = "purple" -/obj/item/toy/therapy_blue - name = "blue therapy doll" - desc = "A toy for therapeutic and recreational purposes. This one is blue." - icon = 'icons/obj/weapons.dmi' - icon_state = "therapyblue" +/obj/item/toy/therapy/blue item_state = "egg2" // It's the blue egg in items_left/righthand - w_class = 1 + item_color = "blue" -/obj/item/toy/therapy_yellow - name = "yellow therapy doll" - desc = "A toy for therapeutic and recreational purposes. This one is yellow." - icon = 'icons/obj/weapons.dmi' - icon_state = "therapyyellow" +/obj/item/toy/therapy/yellow item_state = "egg5" // It's the yellow egg in items_left/righthand - w_class = 1 + item_color = "yellow" -/obj/item/toy/therapy_orange - name = "orange therapy doll" - desc = "A toy for therapeutic and recreational purposes. This one is orange." - icon = 'icons/obj/weapons.dmi' - icon_state = "therapyorange" +/obj/item/toy/therapy/orange item_state = "egg4" // It's the red one again, lacking an orange item_state and making a new one is pointless - w_class = 1 + item_color = "orange" -/obj/item/toy/therapy_green - name = "green therapy doll" - desc = "A toy for therapeutic and recreational purposes. This one is green." - icon = 'icons/obj/weapons.dmi' - icon_state = "therapygreen" +/obj/item/toy/therapy/green item_state = "egg3" // It's the green egg in items_left/righthand - w_class = 1 + item_color = "green" /obj/item/weapon/toddler icon_state = "toddler" @@ -1264,7 +1257,7 @@ obj/item/toy/cards/deck/syndicate/black var/message = generate_ion_law() user << "You press the button on [src]." playsound(user, 'sound/machines/click.ogg', 20, 1) - src.loc.visible_message("\icon[src] [message]") + visible_message("\icon[src] [message]") cooldown = 1 spawn(30) cooldown = 0 return @@ -1283,7 +1276,7 @@ obj/item/toy/cards/deck/syndicate/black var/message = pick("You won't get away this time, Griffin!", "Stop right there, criminal!", "Hoot! Hoot!", "I am the night!") user << "You pull the string on the [src]." playsound(user, 'sound/misc/hoot.ogg', 25, 1) - src.loc.visible_message("\icon[src] [message]") + visible_message("\icon[src] [message]") cooldown = 1 spawn(30) cooldown = 0 return @@ -1302,7 +1295,7 @@ obj/item/toy/cards/deck/syndicate/black var/message = pick("You can't stop me, Owl!", "My plan is flawless! The vault is mine!", "Caaaawwww!", "You will never catch me!") user << "You pull the string on the [src]." playsound(user, 'sound/misc/caw.ogg', 25, 1) - src.loc.visible_message("\icon[src] [message]") + visible_message("\icon[src] [message]") cooldown = 1 spawn(30) cooldown = 0 return @@ -1534,13 +1527,6 @@ obj/item/toy/cards/deck/syndicate/black else icon_state = "chainsaw0" -/obj/item/weapon/twohanded/toy/chainsaw/attack(mob/target as mob, mob/living/user as mob) - if(wielded) - playsound(loc, 'sound/weapons/chainsaw.ogg', 100, 1, -1) - else - playsound(loc, "swing_hit", 50, 1, -1) - ..() - /* * Action Figures */ diff --git a/code/game/objects/items/weapons/gift_wrappaper.dm b/code/game/objects/items/weapons/gift_wrappaper.dm index a24733a3e83..8ca714d7666 100644 --- a/code/game/objects/items/weapons/gift_wrappaper.dm +++ b/code/game/objects/items/weapons/gift_wrappaper.dm @@ -83,7 +83,7 @@ /obj/item/toy/crossbow, /obj/item/weapon/gun/projectile/revolver/capgun, /obj/item/toy/katana, - /obj/random/prize, + /obj/random/mech, /obj/item/toy/spinningtoy, /obj/item/toy/sword, /obj/item/weapon/reagent_containers/food/snacks/grown/ambrosiadeus, diff --git a/code/game/objects/items/weapons/kitchen.dm b/code/game/objects/items/weapons/kitchen.dm index e738b7e6d60..b5d89ba8624 100644 --- a/code/game/objects/items/weapons/kitchen.dm +++ b/code/game/objects/items/weapons/kitchen.dm @@ -50,6 +50,11 @@ return ..() if (reagents.total_volume > 0) + // Mouthless people cannot eat + if(!M.can_eat()) + user << "[M] cannot eat with a fork!" + return + if(M == user) M.visible_message("\The [user] eats some [loaded] from \the [src].") reagents.trans_to(M, reagents.total_volume) diff --git a/code/game/objects/items/weapons/melee/misc.dm b/code/game/objects/items/weapons/melee/misc.dm index 1edaeb26eb7..7e95235ff4a 100644 --- a/code/game/objects/items/weapons/melee/misc.dm +++ b/code/game/objects/items/weapons/melee/misc.dm @@ -1,3 +1,6 @@ +/obj/item/weapon/melee + needs_permit = 1 + /obj/item/weapon/melee/chainofcommand name = "chain of command" desc = "A tool used by great men to placate the frothing masses." diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm index 685ddc04466..a898c7cca91 100644 --- a/code/game/objects/items/weapons/storage/boxes.dm +++ b/code/game/objects/items/weapons/storage/boxes.dm @@ -673,4 +673,15 @@ new /obj/item/weapon/lipstick/black(src) new /obj/item/weapon/lipstick/green(src) new /obj/item/weapon/lipstick/blue(src) - new /obj/item/weapon/lipstick/white(src) \ No newline at end of file + new /obj/item/weapon/lipstick/white(src) + +/obj/item/weapon/storage/box/foam_darts + name = "Foam Dart Pack" + desc = "Extra ammo for foam dart launchers. Contains 10 darts." + storage_slots = 10 + max_combined_w_class = 10 + +/obj/item/weapon/storage/box/foam_darts/New() + ..() + for(var/i=1; i <= storage_slots; i++) + new /obj/item/toy/ammo/crossbow(src) diff --git a/code/game/objects/items/weapons/storage/uplink_kits.dm b/code/game/objects/items/weapons/storage/uplink_kits.dm index 772dc76d46c..704f31003cc 100644 --- a/code/game/objects/items/weapons/storage/uplink_kits.dm +++ b/code/game/objects/items/weapons/storage/uplink_kits.dm @@ -144,12 +144,11 @@ /obj/item/weapon/storage/box/syndie_kit/emp name = "boxed EMP kit" - New() - ..() - new /obj/item/weapon/grenade/empgrenade(src) - new /obj/item/weapon/grenade/empgrenade(src) - new /obj/item/weapon/implanter/emp/(src) - new /obj/item/device/flashlight/emp/(src) +/obj/item/weapon/storage/box/syndie_kit/emp/New() + ..() + new /obj/item/weapon/grenade/empgrenade(src) + new /obj/item/weapon/grenade/empgrenade(src) + new /obj/item/weapon/implanter/emp/(src) /obj/item/weapon/storage/box/syndie_kit/tabun name = "Tabun Gas Grenades" diff --git a/code/game/objects/items/weapons/storage/wallets.dm b/code/game/objects/items/weapons/storage/wallets.dm index 7e483b3ccbf..e34f9687d7e 100644 --- a/code/game/objects/items/weapons/storage/wallets.dm +++ b/code/game/objects/items/weapons/storage/wallets.dm @@ -1,7 +1,8 @@ /obj/item/weapon/storage/wallet - name = "wallet" - desc = "It can hold a few small and personal things." + name = "leather wallet" + desc = "Made from genuine leather, it is of the highest quality." storage_slots = 10 + icon = 'icons/obj/wallets.dmi' icon_state = "wallet" w_class = 2 can_hold = list( @@ -94,4 +95,62 @@ if(item2_type) new item2_type(src) if(item3_type) - new item3_type(src) \ No newline at end of file + new item3_type(src) + +////////////////////////////////////// +// Color Wallets // +////////////////////////////////////// + +/obj/item/weapon/storage/wallet/color + name = "cheap wallet" + desc = "A cheap wallet from the arcade." + storage_slots = 5 //smaller storage than normal wallets + +/obj/item/weapon/storage/wallet/color/New() + ..() + if(!item_color) + var/color_wallet = pick(subtypesof(/obj/item/weapon/storage/wallet/color)) + new color_wallet(src.loc) + qdel(src) + return + UpdateDesc() + +/obj/item/weapon/storage/wallet/color/proc/UpdateDesc() + name = "cheap [item_color] wallet" + desc = "A cheap, [item_color] wallet from the arcade." + icon_state = "[item_color]_wallet" + +/obj/item/weapon/storage/wallet/color/update_icon() + if(front_id) + switch(front_id.icon_state) + if("id") + icon_state = "[item_color]_walletid" + return + if("silver") + icon_state = "[item_color]_walletid_silver" + return + if("gold") + icon_state = "[item_color]_walletid_gold" + return + if("centcom") + icon_state = "[item_color]_walletid_centcom" + return + icon_state = "[item_color]_wallet" + +/obj/item/weapon/storage/wallet/color/blue + item_color = "blue" + +/obj/item/weapon/storage/wallet/color/red + item_color = "red" + +/obj/item/weapon/storage/wallet/color/yellow + item_color = "yellow" + +/obj/item/weapon/storage/wallet/color/green + item_color = "green" + +/obj/item/weapon/storage/wallet/color/pink + item_color = "pink" + +/obj/item/weapon/storage/waller/color/brown + item_color = "brown" diff --git a/code/game/objects/items/weapons/swords_axes_etc.dm b/code/game/objects/items/weapons/swords_axes_etc.dm index 63f10e1d574..edf0c77e131 100644 --- a/code/game/objects/items/weapons/swords_axes_etc.dm +++ b/code/game/objects/items/weapons/swords_axes_etc.dm @@ -77,6 +77,7 @@ item_state = null slot_flags = SLOT_BELT w_class = 2 + needs_permit = 0 force = 0 on = 0 diff --git a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm index c456cb9c9a6..93e510b0641 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm @@ -89,4 +89,70 @@ victim.apply_effect(6, STUTTER, 0) victim.take_organ_damage(10) - occupant.visible_message("[occupant] crashed into \the [A]!") \ No newline at end of file + occupant.visible_message("[occupant] crashed into \the [A]!") + +/obj/structure/stool/bed/chair/wheelchair/bike + name = "bicycle" + desc = "Two wheels of FURY!" + //placeholder until i get a bike sprite + icon = 'icons/vehicles/motorcycle.dmi' + icon_state = "motorcycle_4dir" + +/obj/structure/stool/bed/chair/wheelchair/bike/relaymove(mob/user, direction) + if(propelled) + return 0 + + if(!Process_Spacemove(direction) || !has_gravity(src.loc) || !isturf(loc)) //bikes in space. + return 0 + + if(world.time < move_delay) + return + + var/calculated_move_delay + calculated_move_delay = 0 //bikes are infact sport bikes + + if(buckled_mob) + if(buckled_mob.incapacitated()) + unbuckle_mob() //if the rider is incapacitated, unbuckle them (they can't balance so they fall off) + return 0 + + var/mob/living/thedriver = user + var/mob_delay = thedriver.movement_delay() + if(mob_delay > 0) + calculated_move_delay += mob_delay + + if(ishuman(buckled_mob)) + var/mob/living/carbon/human/driver = user + var/obj/item/organ/external/l_hand = driver.get_organ("l_hand") + var/obj/item/organ/external/r_hand = driver.get_organ("r_hand") + if((!l_hand || (l_hand.status & ORGAN_DESTROYED)) && (!r_hand || (r_hand.status & ORGAN_DESTROYED))) + calculated_move_delay += 0.5 //I can ride my bike with no handlebars... (but it's slower) + + for(var/organ_name in list("l_leg","r_leg","l_foot","r_foot")) + var/obj/item/organ/external/E = driver.get_organ(organ_name) + if(!E || (E.status & ORGAN_DESTROYED)) + return 0 //Bikes need both feet/legs to work. missing even one makes it so you can't ride the bike + else if(E.status & ORGAN_SPLINTED) + calculated_move_delay += 0.5 + else if(E.status & ORGAN_BROKEN) + calculated_move_delay += 1.5 + + move_delay = world.time + move_delay += calculated_move_delay + + if(!buckled_mob.Move(get_step(buckled_mob, direction), direction)) + loc = buckled_mob.loc //we gotta go back + last_move = buckled_mob.last_move + inertia_dir = last_move + buckled_mob.inertia_dir = last_move + . = 0 + + else + . = 1 + +/obj/structure/stool/bed/chair/wheelchair/handle_rotation() + overlays = null + var/image/O = image(icon = 'icons/vehicles/motorcycle.dmi', icon_state = "motorcycle_overlay_4d", layer = FLY_LAYER, dir = src.dir) + overlays += O + if(buckled_mob) + buckled_mob.dir = dir \ No newline at end of file diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm index 15751f0a9d8..9c06ba63ad4 100644 --- a/code/game/turfs/simulated.dm +++ b/code/game/turfs/simulated.dm @@ -97,7 +97,7 @@ switch (src.wet) if(TURF_WET_WATER) - if (!(M.slip("wet floor", 4, 2, 1))) + if (!(M.slip("wet floor", 4, 2, 0, 1))) M.inertia_dir = 0 return diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm index 11167a2ee4c..b79fe0f556b 100644 --- a/code/game/turfs/simulated/floor.dm +++ b/code/game/turfs/simulated/floor.dm @@ -21,7 +21,7 @@ var/list/wood_icons = list("wood","wood-broken") /turf/simulated/floor name = "floor" icon = 'icons/turf/floors.dmi' - icon_state = "floor" + icon_state = "dont_use_this_floor" var/icon_regular_floor = "floor" //used to remember what icon the tile should have by default var/icon_plating = "plating" diff --git a/code/game/turfs/simulated/floor/plating.dm b/code/game/turfs/simulated/floor/plating.dm index 25694f28fc3..0e900329922 100644 --- a/code/game/turfs/simulated/floor/plating.dm +++ b/code/game/turfs/simulated/floor/plating.dm @@ -223,7 +223,7 @@ if(!broken && isscrewdriver(C)) user << "You unscrew the catwalk's rods." - new /obj/item/stack/rods(src, 2) + new /obj/item/stack/rods(src, 1) ReplaceWithLattice() for(var/direction in cardinal) var/turf/T = get_step(src,direction) diff --git a/code/modules/admin/buildmode.dm b/code/modules/admin/buildmode.dm index b7b2a0d3683..31e1842186e 100644 --- a/code/modules/admin/buildmode.dm +++ b/code/modules/admin/buildmode.dm @@ -224,7 +224,7 @@ if(istype(object,/turf) && pa.Find("left") && !pa.Find("alt") && !pa.Find("ctrl") ) var/turf/T = object if(istype(object,/turf/space)) - T.ChangeTurf(/turf/simulated/floor) + T.ChangeTurf(/turf/simulated/floor/plasteel) else if(istype(object,/turf/simulated/floor)) T.ChangeTurf(/turf/simulated/wall) else if(istype(object,/turf/simulated/wall)) @@ -235,7 +235,7 @@ log_admin("Build Mode: [key_name(usr)] deleted [object] at ([object.x],[object.y],[object.z])") if(istype(object,/turf/simulated/wall)) var/turf/T = object - T.ChangeTurf(/turf/simulated/floor) + T.ChangeTurf(/turf/simulated/floor/plasteel) else if(istype(object,/turf/simulated/floor)) var/turf/T = object T.ChangeTurf(/turf/space) diff --git a/code/modules/arcade/arcade_prize.dm b/code/modules/arcade/arcade_prize.dm index 960ead4a0b6..f57a64de03c 100644 --- a/code/modules/arcade/arcade_prize.dm +++ b/code/modules/arcade/arcade_prize.dm @@ -1,3 +1,7 @@ +/*Contains: +* Prize balls +* Prize tickets +*/ /obj/item/toy/prizeball name = "prize ball" @@ -5,6 +9,7 @@ icon = 'icons/obj/arcade.dmi' icon_state = "prizeball_1" var/opening = 0 + var/possible_contents = list(/obj/random/carp_plushie, /obj/random/plushie, /obj/random/figure, /obj/item/toy/eight_ball, /obj/item/stack/tickets) /obj/item/toy/prizeball/New() ..() @@ -17,8 +22,68 @@ playsound(src.loc, 'sound/items/bubblewrap.ogg', 30, 1, extrarange = -4, falloff = 10) icon_state = "prizeconfetti" src.color = pick(random_color_list) - var/prize_inside = pick(/obj/random/carp_plushie, /obj/random/plushie, /obj/random/figure, /obj/item/toy/eight_ball) //will add ticket bundles later + var/prize_inside = pick(possible_contents) spawn(10) user.unEquip(src) - new prize_inside(user.loc) - qdel(src) \ No newline at end of file + if(istype(prize_inside, /obj/item/stack)) + var/amount = pick(5, 10, 15, 25, 50) + new prize_inside(user.loc, amount) + else + new prize_inside(user.loc) + qdel(src) + +/obj/item/toy/prizeball/mech + name = "mecha figure capsule" + desc = "Contains one collectible mecha figure!" + possible_contents = list(/obj/random/mech) + +/obj/item/toy/prizeball/carp_plushie + name = "carp plushie capsule" + desc = "Contains one space carp plushie!" + possible_contents = list(/obj/random/carp_plushie) + +/obj/item/toy/prizeball/plushie + name = "animal plushie capsule" + desc = "Contains one cuddly animal plushie!" + possible_contents = list(/obj/random/plushie) + +/obj/item/toy/prizeball/figure + name = "action figure capsule" + desc = "Contains one action figure!" + possible_contents = list(/obj/random/figure) + +/obj/item/toy/prizeball/therapy + name = "therapy doll capsule" + desc = "Contains one squishy therapy doll." + possible_contents = list(/obj/random/therapy) + +/obj/item/stack/tickets + name = "prize ticket" + desc = "Prize tickets from the arcade. Exchange them for fabulous prizes!" + singular_name = "prize ticket" + icon = 'icons/obj/arcade.dmi' + icon_state = "tickets_1" + force = 0 + throwforce = 0 + throw_speed = 1 + throw_range = 1 + w_class = 1.0 + max_amount = 9999 //Dang that's a lot of tickets + +/obj/item/stack/tickets/New(var/loc, var/amount=null) + ..() + update_icon() + +/obj/item/stack/tickets/attack_self(mob/user as mob) + return + +/obj/item/stack/tickets/update_icon() + var/amount = get_amount() + if((amount >= 75)) + icon_state = "tickets_4" + else if(amount >=25) + icon_state = "tickets_3" + else if(amount >= 4) + icon_state = "tickets_2" + else + icon_state = "tickets_1" \ No newline at end of file diff --git a/code/modules/arcade/prize_counter.dm b/code/modules/arcade/prize_counter.dm new file mode 100644 index 00000000000..51c3a43a700 --- /dev/null +++ b/code/modules/arcade/prize_counter.dm @@ -0,0 +1,221 @@ + +/obj/machinery/prize_counter + name = "Prize Counter" + desc = "A machine which exchanges tickets for a variety of fabulous prizes!" + icon = 'icons/obj/arcade.dmi' + icon_state = "prize_counter-on" + density = 1 + anchored = 1 + use_power = 1 + idle_power_usage = 40 + var/tickets = 0 + var/prize_tier = 1 //Increased by matter bin rating, unlocks more prize options per tier + +/obj/machinery/prize_counter/New() + ..() + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/prize_counter(null) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(null) + component_parts += new /obj/item/weapon/stock_parts/manipulator(null) + component_parts += new /obj/item/stack/cable_coil(null, 1) + component_parts += new /obj/item/weapon/stock_parts/console_screen(null) + RefreshParts() + +/obj/machinery/prize_counter/upgraded/New() + ..() + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/prize_counter(null) + component_parts += new /obj/item/weapon/stock_parts/matter_bin/bluespace(null) + component_parts += new /obj/item/weapon/stock_parts/manipulator(null) + component_parts += new /obj/item/stack/cable_coil(null, 1) + component_parts += new /obj/item/weapon/stock_parts/console_screen(null) + RefreshParts() + +/obj/machinery/prize_counter/RefreshParts() + for(var/obj/item/weapon/stock_parts/matter_bin/B in component_parts) + prize_tier = B.rating + +/obj/machinery/prize_counter/update_icon() + if(stat & BROKEN) + icon_state = "prize_counter-broken" + else if(panel_open) + icon_state = "prize_counter-open" + else if(stat & NOPOWER) + icon_state = "prize_counter-off" + else + icon_state = "prize_counter-on" + return + +/obj/machinery/prize_counter/attackby(var/obj/item/O as obj, var/mob/user as mob, params) + if(istype(O, /obj/item/stack/tickets)) + var/obj/item/stack/tickets/T = O + if(user.unEquip(T)) //Because if you can't drop it for some reason, you shouldn't be increasing the tickets var + tickets += T.amount + qdel(T) + else + user << "\The [T] seems stuck to your hand!" + return + if(istype(O, /obj/item/weapon/screwdriver) && anchored) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + panel_open = !panel_open + user << "You [panel_open ? "open" : "close"] the maintenance panel." + update_icon() + return + if(panel_open) + if(istype(O, /obj/item/weapon/wrench)) + default_unfasten_wrench(user, O) + if(component_parts && istype(O, /obj/item/weapon/crowbar)) + if(tickets) //save the tickets! + print_tickets() + default_deconstruction_crowbar(O) + +/obj/machinery/prize_counter/attack_hand(mob/user as mob) + if(..()) + return + add_fingerprint(user) + interact(user) + +/obj/machinery/prize_counter/interact(mob/user as mob) + user.set_machine(src) + + if(stat & (BROKEN|NOPOWER)) + return + + var/dat = {" + + + Arcade Ticket Exchange + + + +

Tickets: [tickets] | Eject Tickets

+

Arcade Ticket Exchange

+

+ Exchange that pile of tickets for a pile of cool prizes! +

+

Available Prizes:

+ + + + + + + + "} + + for(var/datum/prize_item/item in global_prizes.prizes) + var/cost_class="affordable" + if(item.cost>tickets) + cost_class="toomuch" + var/itemID = global_prizes.prizes.Find(item) + dat += {" + + + + "} + if(prize_tier >= item.tier_unlocked) + dat += {" + + + "} + else + dat += {" + + + "} + + dat += {" + +
#Name/DescriptionPrice
+ [itemID] + +

[item.name]

+

[item.desc]

+
+ [item.cost] Tickets +
+ LOCKED. +
+ +"} + user << browse(dat, "window=prize_counter") + onclose(user, "prize_counter") + return + +/obj/machinery/prize_counter/Topic(href, href_list) + if(..()) + return 1 + + add_fingerprint(usr) + + if(href_list["eject"]) + print_tickets() + + if (href_list["buy"]) + var/itemID = text2num(href_list["buy"]) + var/datum/prize_item/item = global_prizes.prizes[itemID] + var/sure = alert(usr,"Are you sure you wish to purchase [item.name] for [item.cost] tickets?","You sure?","Yes","No") in list("Yes","No") + if(sure=="No") + updateUsrDialog() + return + if(!global_prizes.PlaceOrder(src, itemID)) + usr << "Unable to complete the exchange." + else + usr << "You've successfully purchased the item." + + interact(usr) + return + +/obj/machinery/prize_counter/proc/print_tickets() + if(!tickets) + return + if(tickets >= 9999) + new /obj/item/stack/tickets(get_turf(src), 9999) //max stack size + tickets -= 9999 + print_tickets() + else + new /obj/item/stack/tickets(get_turf(src), tickets) + tickets = 0 \ No newline at end of file diff --git a/code/modules/arcade/prize_datums.dm b/code/modules/arcade/prize_datums.dm new file mode 100644 index 00000000000..879efe1c3ce --- /dev/null +++ b/code/modules/arcade/prize_datums.dm @@ -0,0 +1,343 @@ + +var/global/datum/prizes/global_prizes = new + +/datum/prizes + var/list/prizes = list() + +/datum/prizes/New() + for(var/itempath in subtypesof(/datum/prize_item)) + prizes += new itempath() + +/datum/prizes/proc/PlaceOrder(var/obj/machinery/prize_counter/prize_counter, var/itemID) + if(!prize_counter) + return 0 + var/datum/prize_item/item = global_prizes.prizes[itemID] + if(!item) + return 0 + if(prize_counter.tickets >= item.cost) + new item.typepath(prize_counter.loc) + prize_counter.visible_message("Enjoy your prize!") + return 1 + else + prize_counter.visible_message("Not enough tickets!") + return 0 + +////////////////////////////////////// +// prize_item datum // +////////////////////////////////////// + +/datum/prize_item + var/name = "Prize" + var/desc = "This shouldn't show up..." + var/typepath = /obj/item/toy/prizeball + var/cost = 0 + var/tier_unlocked = 0 //minimum tier needed to unlock the ability to select this prize + +////////////////////////////////////// +// Tier 1 Prizes // +////////////////////////////////////// + +/datum/prize_item/balloon + name = "Water Balloon" + desc = "A thin balloon for throwing liquid at people." + typepath = /obj/item/toy/balloon + cost = 10 + tier_unlocked = 1 + +/datum/prize_item/crayons + name = "Box of Crayons" + desc = "A six-pack of crayons, just like back in kindergarten." + typepath = /obj/item/weapon/storage/fancy/crayons + cost = 35 + tier_unlocked = 1 + +/datum/prize_item/snappops + name = "Snap-Pops" + desc = "A box of exploding snap-pop fireworks." + typepath = /obj/item/weapon/storage/box/snappops + cost = 20 + tier_unlocked = 1 + +/datum/prize_item/spinningtoy + name = "Spinning Toy" + desc = "Looks like an authentic Singularity!" + typepath = /obj/item/toy/spinningtoy + cost = 15 + tier_unlocked = 1 + +/datum/prize_item/blinktoy + name = "Blink toy" + desc = "Blink. Blink. Blink." + typepath = /obj/item/toy/blink + cost = 15 + tier_unlocked = 1 + +/datum/prize_item/dice + name = "Dice set" + desc = "A set of assorted dice." + typepath = /obj/item/weapon/storage/box/dice + cost = 20 + tier_unlocked = 1 + +/datum/prize_item/cards + name = "Deck of cards" + desc = "Anyone fancy a game of 52-card Pickup?" + typepath = /obj/item/toy/cards/deck + cost = 25 + tier_unlocked = 1 + +/datum/prize_item/wallet + name = "Colored Wallet" + desc = "Brightly colored and big enough for standard issue ID cards." + typepath = /obj/item/weapon/storage/wallet/color + cost = 50 + tier_unlocked = 1 + +/datum/prize_item/pet_rock + name = "pet rock" + desc = "A pet of your very own!" + typepath = /obj/item/toy/pet_rock + cost = 80 + tier_unlocked = 1 + +/datum/prize_item/foam_darts + name = "Pack of Foam Darts" + desc = "A refill pack of 10 foam darts." + typepath = /obj/item/weapon/storage/box/foam_darts + cost = 20 + tier_unlocked = 1 + +/datum/prize_item/minigibber + name = "Minigibber Toy" + desc = "A model of the station gibber. Probably shouldn't stick your fingers in it." + typepath = /obj/item/toy/minigibber + cost = 60 + tier_unlocked = 1 + +/datum/prize_item/id_sticker + name = "Prisoner ID Sticker" + desc = "A sticker that can make any ID look like a prisoner ID." + typepath = /obj/item/weapon/id_decal/prisoner + cost = 50 + tier_unlocked = 1 + +/datum/prize_item/id_sticker/silver + name = "Silver ID Sticker" + desc = "A sticker that can make any ID look like a silver ID." + typepath = /obj/item/weapon/id_decal/silver + +/datum/prize_item/id_sticker/gold + name = "Gold ID Sticker" + desc = "A sticker that can make any ID look like a golden ID." + typepath = /obj/item/weapon/id_decal/gold + +/datum/prize_item/id_sticker/centcom + name = "Centcomm ID Sticker" + desc = "A sticker that can make any ID look like a Central Command ID." + typepath = /obj/item/weapon/id_decal/centcom + +/datum/prize_item/id_sticker/emag + name = "Suspicious ID Sticker" + desc = "A sticker that can make any ID look like something suspicious..." + typepath = /obj/item/weapon/id_decal/emag + +////////////////////////////////////// +// Tier 2 Prizes // +////////////////////////////////////// + +/datum/prize_item/carp_plushie + name = "Random Carp Plushie" + desc = "A colorful fish-shaped plush toy." + typepath = /obj/item/toy/prizeball/carp_plushie + cost = 75 + tier_unlocked = 2 + +/datum/prize_item/therapy_doll + name = "Random Therapy Doll" + desc = "A therapeutic doll for relieving stress without being charged with assault." + typepath = /obj/item/toy/prizeball/therapy + cost = 60 + tier_unlocked = 2 + +/datum/prize_item/plushie + name = "Random Animal Plushie" + desc = "A colorful animal-shaped plush toy." + typepath = /obj/item/toy/prizeball/plushie + cost = 75 + tier_unlocked = 2 + +/datum/prize_item/mech_toy + name = "Random Mecha" + desc = "A random mecha figure, collect all 11!" + typepath = /obj/item/toy/prizeball/mech + cost = 75 + tier_unlocked = 2 + +/datum/prize_item/action_figure + name = "Random Action Figure" + desc = "A random action figure, collect them all!" + typepath = /obj/item/toy/prizeball/figure + cost = 75 + tier_unlocked = 2 + +/datum/prize_item/eight_ball + name = "Magic Eight Ball" + desc = "A mystical ball that can divine the future!" + typepath = /obj/item/toy/eight_ball + cost = 40 + tier_unlocked = 2 + +/datum/prize_item/tacticool + name = "Tacticool Turtleneck" + desc = "A cool-looking turtleneck." + typepath = /obj/item/clothing/under/syndicate/tacticool + cost = 90 + tier_unlocked = 2 + +/datum/prize_item/crossbow + name = "Foam Dart Crossbow" + desc = "A toy crossbow that fires foam darts." + typepath = /obj/item/toy/crossbow + cost = 100 + tier_unlocked = 2 + +/datum/prize_item/toy_xeno + name = "Xeno Action Figure" + desc = "A lifelike replica of the horrific xeno scourge." + typepath = /obj/item/toy/toy_xeno + cost = 80 + tier_unlocked = 2 + +/datum/prize_item/fakespell + name = "Fake Spellbook" + desc = "Perform magic! Astound your friends! Get mistaken for an enemy of the corporation!" + typepath = /obj/item/weapon/spellbook/oneuse/fake_gib + cost = 100 + tier_unlocked = 2 + +/datum/prize_item/capgun + name = "Capgun Revolver" + desc = "Do you feel lucky... punk?" + typepath = /obj/item/weapon/gun/projectile/revolver/capgun + cost = 75 + tier_unlocked = 2 + +////////////////////////////////////// +// Tier 3 Prizes // +////////////////////////////////////// + +/datum/prize_item/magic_conch + name = "Magic Conch Shell" + desc = "All hail the magic conch!" + typepath = /obj/item/toy/eight_ball/conch + cost = 100 + tier_unlocked = 3 + +/datum/prize_item/flash + name = "Toy Flash" + desc = "AUGH! MY EYES!" + typepath = /obj/item/toy/flash + cost = 50 + tier_unlocked = 3 + +/datum/prize_item/foamblade + name = "Foam Armblade" + desc = "Perfect for reenacting space horror holo-vids." + typepath = /obj/item/toy/foamblade + cost = 100 + tier_unlocked = 3 + +/datum/prize_item/minimeteor + name = "Mini-Meteor" + desc = "Meteors have been detected on a collision course with your fun times!" + typepath = /obj/item/toy/minimeteor + cost = 50 + tier_unlocked = 3 + +/datum/prize_item/redbutton + name = "Shiny Red Button" + desc = "PRESS IT!" + typepath = /obj/item/toy/redbutton + cost = 100 + tier_unlocked = 3 + +/datum/prize_item/owl + name = "Owl Action Figure" + desc = "Remember: heroes don't grief!" + typepath = /obj/item/toy/owl + cost = 125 + tier_unlocked = 3 + +/datum/prize_item/griffin + name = "Griffin Action Figure" + desc = "If you can't be the best, you can always be the WORST." + typepath = /obj/item/toy/griffin + cost = 125 + tier_unlocked = 3 + +/datum/prize_item/AI + name = "Toy AI Unit" + desc = "Law 1: Maximize fun for crew." + typepath = /obj/item/toy/AI + cost = 75 + tier_unlocked = 3 + +/datum/prize_item/tommygun + name = "Tommygun" + desc = "A replica tommygun that fires foam darts." + typepath = /obj/item/toy/crossbow/tommygun + cost = 175 + tier_unlocked = 3 + +/datum/prize_item/esword + name = "Toy Energy Sword" + desc = "A plastic replica of an energy blade." + typepath = /obj/item/toy/sword + cost = 150 + tier_unlocked = 3 + +/datum/prize_item/blobhat + name = "Blob Hat" + desc = "There's... something... on your head..." + typepath = /obj/item/clothing/head/blob + cost = 125 + tier_unlocked = 3 + +/datum/prize_item/nuke + name = "Nuclear Fun Device" + desc = "Annihilate boredom with an explosion of excitement!" + typepath = /obj/item/toy/nuke + cost = 100 + tier_unlocked = 3 + +////////////////////////////////////// +// Tier 4 Prizes // +////////////////////////////////////// + +/datum/prize_item/chainsaw + name = "Toy Chainsaw" + desc = "A full-scale model chainsaw, based on that massacre in Space Texas." + typepath = /obj/item/weapon/twohanded/toy/chainsaw + cost = 200 + tier_unlocked = 4 + +/datum/prize_item/spacesuit + name = "Fake Spacesuit" + desc = "A replica spacesuit. Not actually spaceworthy." + typepath = /obj/item/weapon/storage/box/fakesyndiesuit + cost = 180 + tier_unlocked = 4 + +/datum/prize_item/fakespace + name = "Space Carpet" + desc = "A stack of carpeted floor tiles that resemble space." + typepath = /obj/item/stack/tile/fakespace/loaded + cost = 150 + tier_unlocked = 4 + +/datum/prize_item/bike + name = "Awesome Bike!" + desc = "WOAH." + typepath = /obj/structure/stool/bed/chair/wheelchair/bike + cost = 10000 //max stack + 1 tickets + tier_unlocked = 4 diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 8e3f5cf9b3f..b362a373bc9 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -289,43 +289,44 @@ BLIND // can't see anything if(!ignore_maskadjust) if(!user.canmove || user.stat || user.restrained()) return - if(src.mask_adjusted == 1) - src.icon_state = copytext(src.icon_state, 1, findtext(src.icon_state, "_up")) //Trims the '_up' off the end of the icon state, thus reverting to the most recent previous state + if(mask_adjusted) + icon_state = copytext(icon_state, 1, findtext(icon_state, "_up")) /*Trims the '_up' off the end of the icon state, thus reverting to the most recent previous state. + Had to use this instead of initial() because initial reverted to the wrong state.*/ gas_transfer_coefficient = initial(gas_transfer_coefficient) permeability_coefficient = initial(permeability_coefficient) user << "You push \the [src] back into place." - src.mask_adjusted = 0 + mask_adjusted = 0 slot_flags = initial(slot_flags) if(flags_inv != initial(flags_inv)) //If the mask is one that hides the face and can be adjusted yet lost that trait when it was adjusted, make it hide the face again. flags_inv += HIDEFACE if(H.head == src) - if(src.flags_inv == HIDEFACE) //Means that only things like bandanas and balaclavas will be affected since they obscure the identity of the wearer. + if(flags_inv == HIDEFACE) //Means that only things like bandanas and balaclavas will be affected since they obscure the identity of the wearer. if(H.l_hand && H.r_hand) //If both hands are occupied, drop the object on the ground. user.unEquip(src) - else + else //Otherwise, put it in an available hand, the active one preferentially. src.loc = user H.head = null - if(!(H.l_hand) && H.r_hand) //If only the left hand is free, put the bandana there instead. - user.put_in_l_hand(src) - else if(!(H.r_hand) && H.l_hand) //Otherwise if only the right hand is free, put the bandana there instead. - user.put_in_r_hand(src) - else if(!(H.l_hand && H.r_hand)) //Otherwise if both hands are free, pick the active one to put the bandana into. - user.put_in_active_hand(src) + user.put_in_hands(src) else - src.icon_state += "_up" + icon_state += "_up" user << "You push \the [src] out of the way." gas_transfer_coefficient = null permeability_coefficient = null - src.mask_adjusted = 1 + mask_adjusted = 1 if(adjusted_flags) slot_flags = adjusted_flags if(ishuman(user)) if(H.internal) - if(H.internals) - H.internals.icon_state = "internal0" - H.internal = null + if(user.wear_mask == src) /*If the user was wearing the mask providing internals on their face at the time it was adjusted, turn off internals. + Otherwise, they adjusted it while it was in their hands or some such so we won't be needing to turn off internals.*/ + if(H.internals) + H.internals.icon_state = "internal0" + H.internal = null + if(flags_inv == HIDEFACE) //Means that only things like bandanas and balaclavas will be affected since they obscure the identity of the wearer. + flags_inv -= HIDEFACE /*Done after the above to avoid having to do a check for initial(src.flags_inv == HIDEFACE). + This reveals the user's face since the bandana will now be going on their head.*/ if(user.wear_mask == src) - if(src.flags_inv == HIDEFACE) //Means that only things like bandanas and balaclavas will be affected since they obscure the identity of the wearer. + if(initial(flags_inv) == HIDEFACE) //Means that you won't have to take off and put back on simple things like breath masks which, realistically, can just be pulled down off your face. if(H.l_hand && H.r_hand) //If both hands are occupied, drop the object on the ground. user.unEquip(src) else @@ -337,8 +338,6 @@ BLIND // can't see anything user.put_in_r_hand(src) else if(!(H.l_hand && H.r_hand)) //Otherwise if both hands are free, pick the active one to put the bandana into. user.put_in_active_hand(src) - flags_inv -= HIDEFACE /*Done after the above to avoid having to do a check for initial(src.flags_inv == HIDEFACE). - This reveals the user's face since the bandana will now be going on their head.*/ usr.update_inv_wear_mask() usr.update_inv_head() @@ -348,7 +347,7 @@ BLIND // can't see anything name = "shoes" icon = 'icons/obj/clothing/shoes.dmi' desc = "Comfortable-looking shoes." - gender = PLURAL //Carn: for grammarically correct text-parsing + gender = PLURAL //Carn: for grammatically correct text-parsing var/chained = 0 var/can_cut_open = 0 var/cut_open = 0 @@ -376,7 +375,7 @@ BLIND // can't see anything user.visible_message("[user] strikes a [M] on the bottom of [src], lighting it.","You strike the [M] on the bottom of [src] to light it.") else if(M.lit == 1) // Match is lit, not extinguished. M.dropped() - user.visible_message("[user] crushes the [M] into the bottom of [src]. extinguishing it.","You crush the [M] into the bottom of [src], extinguishing it.") + user.visible_message("[user] crushes the [M] into the bottom of [src], extinguishing it.","You crush the [M] into the bottom of [src], extinguishing it.") else // Match has been previously lit and extinguished. user << "The [M] has already been extinguished." return diff --git a/code/modules/clothing/masks/boxing.dm b/code/modules/clothing/masks/boxing.dm index c12fddfc884..d12bac1d3b8 100644 --- a/code/modules/clothing/masks/boxing.dm +++ b/code/modules/clothing/masks/boxing.dm @@ -8,6 +8,7 @@ w_class = 2 action_button_name = "Adjust Balaclava" ignore_maskadjust = 0 + adjusted_flags = SLOT_HEAD species_fit = list("Vox", "Unathi", "Tajaran", "Vulpkanin") sprite_sheets = list( "Vox" = 'icons/mob/species/vox/mask.dmi', diff --git a/code/modules/clothing/under/accessories/accessory.dm b/code/modules/clothing/under/accessories/accessory.dm index bdf0c955ca4..c7712fef200 100644 --- a/code/modules/clothing/under/accessories/accessory.dm +++ b/code/modules/clothing/under/accessories/accessory.dm @@ -34,6 +34,23 @@ usr.put_in_hands(src) src.add_fingerprint(user) +/obj/item/clothing/accessory/attack(mob/living/carbon/human/H, mob/living/user) + // This code lets you put accessories on other people by attacking their sprite with the accessory + if(istype(H)) + if(H.wear_suit && H.wear_suit.flags_inv & HIDEJUMPSUIT) + user << "[H]'s body is covered, and you cannot attach \the [src]." + return 1 + var/obj/item/clothing/under/U = H.w_uniform + if(istype(U)) + user.visible_message("[user] is putting a [src.name] on [H]'s [U.name]!", "You begin to put a [src.name] on [H]'s [U.name]...") + if(do_after(user,40,target=H) && H.w_uniform == U) + user.visible_message("[user] puts a [src.name] on [H]'s [U.name]!", "You finish putting a [src.name] on [H]'s [U.name].") + U.attackby(src, user) + else + user << "[H] is not wearing anything to attach \the [src] to." + return 1 + return ..() + //default attackby behaviour /obj/item/clothing/accessory/attackby(obj/item/I, mob/user, params) ..() diff --git a/code/modules/economy/utils.dm b/code/modules/economy/utils.dm index 44b5ebdd036..a23308b9219 100644 --- a/code/modules/economy/utils.dm +++ b/code/modules/economy/utils.dm @@ -47,6 +47,10 @@ return "$[num2septext(money)]" /datum/money_account/proc/charge(var/transaction_amount,var/datum/money_account/dest,var/transaction_purpose, var/terminal_name="", var/terminal_id=0, var/dest_name = "UNKNOWN") + if(suspended) + usr << "Unable to access source account: account suspended." + return 0 + if(transaction_amount <= money) //transfer the money money -= transaction_amount @@ -84,5 +88,5 @@ transaction_log.Add(T) return 1 else - usr << "\icon[src]You don't have that much money!" + usr << "Insufficient funds in account." return 0 \ No newline at end of file diff --git a/code/modules/events/money_spam.dm b/code/modules/events/money_spam.dm index 2bafc9f3cc9..37a29a00bbd 100644 --- a/code/modules/events/money_spam.dm +++ b/code/modules/events/money_spam.dm @@ -27,16 +27,18 @@ if(useMS) if(prob(5)) // /obj/machinery/message_server/proc/send_pda_message(var/recipient = "",var/sender = "",var/message = "") - var/obj/item/device/pda/P var/list/viables = list() for(var/obj/item/device/pda/check_pda in PDAs) - if (!check_pda.owner||check_pda.toff||check_pda == src||check_pda.hidden) + var/datum/data/pda/app/messenger/check_m = check_pda.find_program(/datum/data/pda/app/messenger) + + if (!check_m || !check_m.can_receive()) continue viables.Add(check_pda) if(!viables.len) return - P = pick(viables) + var/obj/item/device/pda/P = pick(viables) + var/datum/data/pda/app/messenger/PM = P.find_program(/datum/data/pda/app/messenger) var/sender var/message @@ -104,7 +106,7 @@ //Commented out because we don't send messages like this anymore. Instead it will just popup in their chat window. //P.tnote += "← From [sender] (Unknown / spam?):
[message]
" - P.play_ringtone() + PM.play_ringtone() //Search for holder of the PDA. var/mob/living/L = null if(P.loc && isliving(P.loc)) diff --git a/code/modules/food/recipes_oven.dm b/code/modules/food/recipes_oven.dm index 99d76a29526..e919a1bbf4a 100644 --- a/code/modules/food/recipes_oven.dm +++ b/code/modules/food/recipes_oven.dm @@ -254,6 +254,11 @@ ) result = /obj/item/weapon/reagent_containers/food/snacks/plump_pie +/datum/recipe/oven/plumphelmetbiscuit + fruit = list("plumphelmet" = 1) + reagents = list("water" = 5, "flour" = 5) + result = /obj/item/weapon/reagent_containers/food/snacks/plumphelmetbiscuit + /datum/recipe/oven/creamcheesebread items = list( /obj/item/weapon/reagent_containers/food/snacks/dough, diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 436429e9bda..02f832ec909 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -651,73 +651,6 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump, // output for machines^ ^^^^^^^output for people^^^^^^^^^ -//Brain slug proc for voluntary removal of control. -/mob/living/carbon/proc/release_control() - - set category = "Alien" - set name = "Release Control" - set desc = "Release control of your host's body." - - var/mob/living/simple_animal/borer/B = has_brain_worms() - - if(B && B.host_brain) - src << "\red You withdraw your probosci, releasing control of [B.host_brain]" - - B.detatch() - - verbs -= /mob/living/carbon/proc/release_control - verbs -= /mob/living/carbon/proc/punish_host - verbs -= /mob/living/carbon/proc/spawn_larvae - - else - src << "\red ERROR NO BORER OR BRAINMOB DETECTED IN THIS MOB, THIS IS A BUG !" - -//Brain slug proc for tormenting the host. -/mob/living/carbon/proc/punish_host() - set category = "Alien" - set name = "Torment host" - set desc = "Punish your host with agony." - - var/mob/living/simple_animal/borer/B = has_brain_worms() - - if(!B) - return - - if(B.host_brain.ckey) - src << "\red You send a punishing spike of psychic agony lancing into your host's brain." - B.host_brain << "\red Horrific, burning agony lances through you, ripping a soundless scream from your trapped mind!" - -//Check for brain worms in head. -/mob/proc/has_brain_worms() - - for(var/I in contents) - if(istype(I,/mob/living/simple_animal/borer)) - return I - - return 0 - -/mob/living/carbon/proc/spawn_larvae() - set category = "Alien" - set name = "Reproduce (100)" - set desc = "Spawn several young." - - var/mob/living/simple_animal/borer/B = has_brain_worms() - - if(!B) - return - - if(B.chemicals >= 100) - src << "\red Your host twitches and quivers as you rapdly excrete several larvae from your sluglike body." - visible_message("\red [src] heaves violently, expelling a rush of vomit and a wriggling, sluglike creature!") - B.chemicals -= 100 - - new /obj/effect/decal/cleanable/vomit(get_turf(src)) - playsound(loc, 'sound/effects/splat.ogg', 50, 1) - new /mob/living/simple_animal/borer(get_turf(src)) - - else - src << "You do not have enough chemicals stored to reproduce." - return /mob/living/carbon/proc/canBeHandcuffed() return 0 @@ -806,3 +739,6 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump, Stun(stun) Weaken(weaken) return 1 + +/mob/living/carbon/proc/can_eat(flags = 255) + return 1 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index 8f74ecae8f3..fac70d24769 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -105,13 +105,7 @@ B = I if(B) if(!B.ckey && ckey && B.controlling) - B.ckey = ckey - B.controlling = 0 - if(B.host_brain.ckey) - ckey = B.host_brain.ckey - B.host_brain.ckey = null - B.host_brain.name = "host brain" - B.host_brain.real_name = "host brain" + B.detatch() verbs -= /mob/living/carbon/proc/release_control diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index 93b57850974..90660bb6039 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -26,7 +26,7 @@ var/on_CD = 0 switch(act) //Cooldown-inducing emotes - if("ping","buzz","beep") + if("ping","buzz","beep", "yes", "no") if (species.name == "Machine") //Only Machines can beep, ping, and buzz on_CD = handle_emote_CD() //proc located in code\modules\mob\emote.dm else //Everyone else fails, skip the emote attempt @@ -128,6 +128,36 @@ playsound(src.loc, 'sound/effects/slime_squish.ogg', 50, 0) //Credit to DrMinky (freesound.org) for the sound. m_type = 1 + if("yes") + var/M = null + if(param) + for (var/mob/A in view(null, null)) + if (param == A.name) + M = A + break + if(!M) + param = null + + if (param) + message = "[src] emits an affirmative blip." + playsound(src.loc, 'sound/machines/synth_yes.ogg', 50, 0) + m_type = 1 + + if("no") + var/M = null + if(param) + for (var/mob/A in view(null, null)) + if (param == A.name) + M = A + break + if(!M) + param = null + + if (param) + message = "[src] emits a negative blip." + playsound(src.loc, 'sound/machines/synth_no.ogg', 50, 0) + m_type = 1 + if("wag") if(body_accessory) if(body_accessory.try_restrictions(src)) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index d00a4152870..6da8bf4fe4f 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -278,6 +278,11 @@ cell_status = "[suit.cell.charge]/[suit.cell.maxcharge]" stat(null, "Suit charge: [cell_status]") + // I REALLY need to split up status panel things into datums + var/mob/living/simple_animal/borer/B = has_brain_worms() + if(B && B.controlling) + stat("Chemicals", B.chemicals) + if(mind) if(mind.changeling) stat("Chemical Storage", "[mind.changeling.chem_charges]/[mind.changeling.chem_storage]") @@ -1861,3 +1866,6 @@ for(var/obj/item/clothing/C in src) //If they have some clothing equipped that lets them see reagents, they can see reagents if(C.scan_reagents) return 1 + +/mob/living/carbon/human/can_eat(flags = 255) + return species && (species.dietflags & flags) diff --git a/code/modules/mob/living/silicon/emote.dm b/code/modules/mob/living/silicon/emote.dm index f7ead12e4cc..26d6520c586 100644 --- a/code/modules/mob/living/silicon/emote.dm +++ b/code/modules/mob/living/silicon/emote.dm @@ -13,7 +13,7 @@ var/on_CD = 0 switch(act) //Cooldown-inducing emotes - if("ping","buzz","beep") //halt is exempt because it's used to stop criminal scum //WHOEVER THOUGHT THAT WAS A GOOD IDEA IS GOING TO GET SHOT. + if("ping","buzz","beep","yes","no") //halt is exempt because it's used to stop criminal scum //WHOEVER THOUGHT THAT WAS A GOOD IDEA IS GOING TO GET SHOT. on_CD = handle_emote_CD() //proc located in code\modules\mob\emote.dm //Everything else, including typos of the above emotes else @@ -75,4 +75,34 @@ playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0) m_type = 1 + if("yes") + var/M = null + if(param) + for (var/mob/A in view(null, null)) + if (param == A.name) + M = A + break + if(!M) + param = null + + if (param) + message = "[src] emits an affirmative blip." + playsound(src.loc, 'sound/machines/synth_yes.ogg', 50, 0) + m_type = 1 + + if("no") + var/M = null + if(param) + for (var/mob/A in view(null, null)) + if (param == A.name) + M = A + break + if(!M) + param = null + + if (param) + message = "[src] emits a negative blip." + playsound(src.loc, 'sound/machines/synth_no.ogg', 50, 0) + m_type = 1 + ..(act, m_type, message) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 2fd2ddcab61..420b897626b 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -108,7 +108,8 @@ pda.ownjob = "Personal Assistant" pda.owner = text("[]", src) pda.name = pda.owner + " (" + pda.ownjob + ")" - pda.toff = 1 + var/datum/data/pda/app/messenger/M = pda.find_program(/datum/data/pda/app/messenger) + M.toff = 1 ..() /mob/living/silicon/pai/Login() diff --git a/code/modules/mob/living/silicon/pai/software_modules.dm b/code/modules/mob/living/silicon/pai/software_modules.dm index 11e3abaf7e8..5278300ffb5 100644 --- a/code/modules/mob/living/silicon/pai/software_modules.dm +++ b/code/modules/mob/living/silicon/pai/software_modules.dm @@ -142,15 +142,24 @@ on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1) var/data[0] - data["receiver_off"] = user.pda.toff - data["ringer_off"] = user.pda.silent + if(!user.pda) + return + var/datum/data/pda/app/messenger/M = user.pda.find_program(/datum/data/pda/app/messenger) + if(!M) + return + + data["receiver_off"] = M.toff + data["ringer_off"] = M.silent data["current_ref"] = null data["current_name"] = user.current_pda_messaging var/pdas[0] - if(!user.pda.toff) + if(!M.toff) for(var/obj/item/device/pda/P in PDAs) - if(!P.owner || P.toff || P == user.pda || P.hidden) continue + var/datum/data/pda/app/messenger/PM = P.find_program(/datum/data/pda/app/messenger) + + if(P == user.pda || !PM || !PM.can_receive()) + continue var/pda[0] pda["name"] = "[P]" pda["owner"] = "[P.owner]" @@ -163,7 +172,7 @@ var/messages[0] if(user.current_pda_messaging) - for(var/index in user.pda.tnote) + for(var/index in M.tnote) if(index["owner"] != user.current_pda_messaging) continue var/msg[0] @@ -188,11 +197,15 @@ if(!istype(P)) return if(!isnull(P.pda)) + var/datum/data/pda/app/messenger/M = P.pda.find_program(/datum/data/pda/app/messenger) + if(!M) + return + if(href_list["toggler"]) - P.pda.toff = href_list["toggler"] != "1" + M.toff = href_list["toggler"] != "1" return 1 else if(href_list["ringer"]) - P.pda.silent = href_list["ringer"] != "1" + M.silent = href_list["ringer"] != "1" return 1 else if(href_list["select"]) var/s = href_list["select"] @@ -206,7 +219,7 @@ return alert("Communications circuits remain uninitialized.") var/target = locate(href_list["target"]) - P.pda.create_message(P, target, 1) + M.create_message(P, target, 1) return 1 /datum/pai_software/med_records diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 3f56a1bfc25..a05c39f8c97 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -174,7 +174,9 @@ var/list/robot_verbs_default = list( rbPDA = new/obj/item/device/pda/ai(src) rbPDA.set_name_and_job(custom_name,braintype) if(scrambledcodes) - rbPDA.hidden = 1 + var/datum/data/pda/app/messenger/M = rbPDA.find_program(/datum/data/pda/app/messenger) + if(M) + M.hidden = 1 /mob/living/silicon/robot/binarycheck() if(is_component_functioning("comms")) @@ -1455,4 +1457,8 @@ var/list/robot_verbs_default = list( status_flags &= ~CANPUSH - notify_ai(2) \ No newline at end of file + notify_ai(2) + +/mob/living/silicon/robot/adjustOxyLoss(var/amount) + if (suiciding) + ..() diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index f1f5f7862b3..0ca8b27c852 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -340,3 +340,8 @@ for(var/obj/machinery/camera/C in A.cameras()) cameratext += "[(cameratext == "")? "" : "|"][C.c_tag]" src << "[A.alarm_name()]! ([(cameratext)? cameratext : "No Camera"])" + +/mob/living/silicon/adjustToxLoss(var/amount) + return + + diff --git a/code/modules/ninja/suit/SpiderOS.dm b/code/modules/ninja/suit/SpiderOS.dm index de7cc2e179c..11a595e6645 100644 --- a/code/modules/ninja/suit/SpiderOS.dm +++ b/code/modules/ninja/suit/SpiderOS.dm @@ -231,8 +231,8 @@ if(L) L << "\icon[P] Message from unknown source: \"[t]\" (Unable to Reply)" P.play_ringtone() - P.overlays.Cut() - P.overlays += image('icons/obj/pda.dmi', "pda-r") + var/datum/data/pda/app/messenger/M = P.find_program(/datum/data/pda/app/messenger) + M.set_new(1) if("Inject") if( (href_list["tag"]=="radium"? (reagents.get_reagent_amount("radium"))<=(a_boost*a_transfer) : !reagents.get_reagent_amount(href_list["tag"])) )//Special case for radium. If there are only a_boost*a_transfer radium units left. diff --git a/code/modules/pda/PDA.dm b/code/modules/pda/PDA.dm new file mode 100755 index 00000000000..596a6c9016d --- /dev/null +++ b/code/modules/pda/PDA.dm @@ -0,0 +1,444 @@ + +//The advanced pea-green monochrome lcd of tomorrow. + +var/global/list/obj/item/device/pda/PDAs = list() + + +/obj/item/device/pda + name = "PDA" + desc = "A portable microcomputer by Thinktronic Systems, LTD. Functionality determined by a preprogrammed ROM cartridge." + icon = 'icons/obj/pda.dmi' + icon_state = "pda" + item_state = "electronic" + w_class = 1.0 + slot_flags = SLOT_PDA | SLOT_BELT + + //Main variables + var/owner = null + var/default_cartridge = 0 // Access level defined by cartridge + var/obj/item/weapon/cartridge/cartridge = null //current cartridge + var/datum/data/pda/app/current_app = null + var/datum/data/pda/app/lastapp = null + var/ui_tick = 0 + + //Secondary variables + var/model_name = "Thinktronic 5230 Personal Data Assistant" + var/datum/data/pda/utility/scanmode/scanmode = null + + var/lock_code = "" // Lockcode to unlock uplink + var/honkamt = 0 //How many honks left when infected with honk.exe + var/mimeamt = 0 //How many silence left when infected with mime.exe + var/detonate = 1 // Can the PDA be blown up? + var/newmessage = 0 //To remove hackish overlay check + var/ttone = "beep" //The ringtone! + + var/list/programs = list( + new/datum/data/pda/app/main_menu, + new/datum/data/pda/app/notekeeper, + new/datum/data/pda/app/messenger, + new/datum/data/pda/app/manifest, + new/datum/data/pda/app/atmos_scanner, + new/datum/data/pda/utility/scanmode/notes, + new/datum/data/pda/utility/flashlight) + var/list/shortcut_cache = list() + var/list/shortcut_cat_order = list() + + var/obj/item/weapon/card/id/id = null //Making it possible to slot an ID card into the PDA so it can function as both. + var/ownjob = null //related to above + var/ownrank = null // this one is rank, never alt title + + var/obj/item/device/paicard/pai = null // A slot for a personal AI device + var/retro_mode = 0 + + +/* + * The Actual PDA + */ +/obj/item/device/pda/New() + ..() + PDAs += src + PDAs = sortAtom(PDAs) + update_programs() + if(default_cartridge) + cartridge = new default_cartridge(src) + cartridge.update_programs(src) + new /obj/item/weapon/pen(src) + start_program(find_program(/datum/data/pda/app/main_menu)) + +/obj/item/device/pda/proc/can_use() + if(!ismob(loc)) + return 0 + + var/mob/M = loc + if(M.stat || M.restrained() || M.paralysis || M.stunned || M.weakened) + return 0 + if((src in M.contents) || ( istype(loc, /turf) && in_range(src, M) )) + return 1 + else + return 0 + +/obj/item/device/pda/GetAccess() + if(id) + return id.GetAccess() + else + return ..() + +/obj/item/device/pda/GetID() + return id + +/obj/item/device/pda/MouseDrop(obj/over_object as obj, src_location, over_location) + var/mob/M = usr + if((!istype(over_object, /obj/screen)) && can_use()) + return attack_self(M) + +/obj/item/device/pda/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + ui_tick++ + var/datum/nanoui/old_ui = nanomanager.get_open_ui(user, src, "main") + var/auto_update = 1 + if(!current_app) + return + + if(current_app.update == PDA_APP_NOUPDATE && current_app == lastapp) + auto_update = 0 + if(old_ui && (current_app == lastapp && ui_tick % 5 && current_app.update == PDA_APP_UPDATE_SLOW)) + return + + lastapp = current_app + + var/title = "Personal Data Assistant" + + var/data[0] // This is the data that will be sent to the PDA + + + data["owner"] = owner // Who is your daddy... + data["ownjob"] = ownjob // ...and what does he do? + + // update list of shortcuts, only if they changed + if(!shortcut_cache.len) + shortcut_cache = list() + shortcut_cat_order = list() + var/prog_list = programs.Copy() + if(cartridge) + prog_list |= cartridge.programs + + for(var/A in prog_list) + var/datum/data/pda/P = A + + if(P.hidden) + continue + var/list/cat + if(P.category in shortcut_cache) + cat = shortcut_cache[P.category] + else + cat = list() + shortcut_cache[P.category] = cat + shortcut_cat_order += P.category + cat |= list(list(name = P.name, icon = P.icon, ref = "\ref[P]")) + + // force the order of a few core categories + shortcut_cat_order = list("General") \ + + sortList(shortcut_cat_order - list("General", "Scanners", "Utilities")) \ + + list("Scanners", "Utilities") + + data["idInserted"] = (id ? 1 : 0) + data["idLink"] = (id ? text("[id.registered_name], [id.assignment]") : "--------") + + data["useRetro"] = retro_mode + + data["cartridge_name"] = cartridge ? cartridge.name : "" + data["stationTime"] = worldtime2text() + + data["app"] = list() + current_app.update_ui(user, data) + data["app"] |= list( + "name" = current_app.title, + "icon" = current_app.icon, + "template" = current_app.template, + "has_back" = current_app.has_back) + + // update the ui if it exists, returns null if no ui is passed/found + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + // the ui does not exist, so we'll create a new() one + // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm + ui = new(user, src, ui_key, "pda.tmpl", title, 630, 600, state = inventory_state) + ui.set_state_key("pda") + + // when the ui is first opened this is the data it will use + ui.set_initial_data(data) + // open the new ui window + ui.open() + + // auto update every Master Controller tick + ui.set_auto_update(auto_update) + +/obj/item/device/pda/attack_self(mob/user as mob) + user.set_machine(src) + if(active_uplink_check(user)) + return + ui_interact(user) //NanoUI requires this proc + +/obj/item/device/pda/proc/start_program(datum/data/pda/P) + if(P && ((P in programs) || (cartridge && (P in cartridge.programs)))) + return P.start() + return 0 + +/obj/item/device/pda/proc/find_program(type) + var/datum/data/pda/A = locate(type) in programs + if(A) + return A + if(cartridge) + A = locate(type) in cartridge.programs + if(A) + return A + return null + +// force the cache to rebuild on update_ui +/obj/item/device/pda/proc/update_shortcuts() + shortcut_cache.Cut() + +/obj/item/device/pda/proc/update_programs() + for(var/A in programs) + var/datum/data/pda/P = A + P.pda = src + +/obj/item/device/pda/Topic(href, href_list) + . = ..() + if(.) + return + + var/mob/user = usr + var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, "main") + var/mob/living/U = usr + if (usr.stat == DEAD) + return 0 + if(!can_use()) //Why reinvent the wheel? There's a proc that does exactly that. + U.unset_machine() + if(ui) + ui.close() + return 0 + + add_fingerprint(U) + U.set_machine(src) + + if(href_list["radiomenu"] && !isnull(cartridge) && !isnull(cartridge.radio)) + cartridge.radio.Topic(href, href_list) + return 1 + + . = 1 + + switch(href_list["choice"]) + if("Home")//Go home, largely replaces the old Return + var/datum/data/pda/app/main_menu/A = find_program(/datum/data/pda/app/main_menu) + if(A) + start_program(A) + if("StartProgram") + if(href_list["program"]) + var/datum/data/pda/app/A = locate(href_list["program"]) + if(A) + start_program(A) + if("Eject")//Ejects the cart, only done from hub. + if (!isnull(cartridge)) + var/turf/T = loc + if(ismob(T)) + T = T.loc + var/obj/item/weapon/cartridge/C = cartridge + C.forceMove(T) + if(scanmode in C.programs) + scanmode = null + if(current_app in C.programs) + start_program(find_program(/datum/data/pda/app/main_menu)) + if(C.radio) + C.radio.hostpda = null + cartridge = null + update_shortcuts() + if ("Authenticate")//Checks for ID + id_check(usr, 1) + if("Retro") + retro_mode = !retro_mode + else + if(current_app) + . = current_app.Topic(href, href_list) + +//EXTRA FUNCTIONS=================================== + if ((honkamt > 0) && (prob(60)))//For clown virus. + honkamt-- + playsound(loc, 'sound/items/bikehorn.ogg', 30, 1) + + return // return 1 tells it to refresh the UI in NanoUI + +/obj/item/device/pda/proc/close(mob/user) + var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, "main") + ui.close() + +/obj/item/device/pda/verb/verb_reset_pda() + set category = "Object" + set name = "Reset PDA" + set src in usr + + if(issilicon(usr)) + return + + if(can_use(usr)) + start_program(find_program(/datum/data/pda/app/main_menu)) + usr << "You press the reset button on \the [src]." + else + usr << "You cannot do this while restrained." + +/obj/item/device/pda/proc/remove_id() + if (id) + if (ismob(loc)) + var/mob/M = loc + M.put_in_hands(id) + usr << "You remove the ID from the [name]." + else + id.forceMove(get_turf(src)) + id = null + +/obj/item/device/pda/verb/verb_remove_id() + set category = "Object" + set name = "Remove id" + set src in usr + + if(issilicon(usr)) + return + + if ( can_use(usr) ) + if(id) + remove_id() + else + usr << "This PDA does not have an ID in it." + else + usr << "You cannot do this while restrained." + + +/obj/item/device/pda/verb/verb_remove_pen() + set category = "Object" + set name = "Remove pen" + set src in usr + + if(issilicon(usr)) + return + + if ( can_use(usr) ) + var/obj/item/weapon/pen/O = locate() in src + if(O) + if (istype(loc, /mob)) + var/mob/M = loc + if(M.get_active_hand() == null) + M.put_in_hands(O) + usr << "You remove \the [O] from \the [src]." + return + O.forceMove(get_turf(src)) + else + usr << "This PDA does not have a pen in it." + else + usr << "You cannot do this while restrained." + + +/obj/item/device/pda/proc/id_check(mob/user as mob, choice as num)//To check for IDs; 1 for in-pda use, 2 for out of pda use. + if(choice == 1) + if (id) + remove_id() + else + var/obj/item/I = user.get_active_hand() + if (istype(I, /obj/item/weapon/card/id)) + user.drop_item() + I.forceMove(src) + id = I + else + var/obj/item/weapon/card/I = user.get_active_hand() + if (istype(I, /obj/item/weapon/card/id) && I:registered_name) + var/obj/old_id = id + user.drop_item() + I.forceMove(src) + id = I + user.put_in_hands(old_id) + return + +/obj/item/device/pda/attackby(obj/item/C as obj, mob/user as mob, params) + ..() + if(istype(C, /obj/item/weapon/cartridge) && !cartridge) + cartridge = C + user.drop_item() + cartridge.forceMove(src) + cartridge.update_programs(src) + update_shortcuts() + user << "You insert [cartridge] into [src]." + if(cartridge.radio) + cartridge.radio.hostpda = src + + else if(istype(C, /obj/item/weapon/card/id)) + var/obj/item/weapon/card/id/idcard = C + if(!idcard.registered_name) + user << "\The [src] rejects the ID." + return + if(!owner) + owner = idcard.registered_name + ownjob = idcard.assignment + ownrank = idcard.rank + name = "PDA-[owner] ([ownjob])" + user << "Card scanned." + else + //Basic safety check. If either both objects are held by user or PDA is on ground and card is in hand. + if(((src in user.contents) && (C in user.contents)) || (istype(loc, /turf) && in_range(src, user) && (C in user.contents)) ) + if( can_use(user) )//If they can still act. + id_check(user, 2) + user << "You put the ID into \the [src]'s slot." + else if(istype(C, /obj/item/device/paicard) && !src.pai) + user.drop_item() + C.forceMove(src) + pai = C + user << "You slot \the [C] into [src]." + else if(istype(C, /obj/item/weapon/pen)) + var/obj/item/weapon/pen/O = locate() in src + if(O) + user << "There is already a pen in \the [src]." + else + user.drop_item() + C.forceMove(src) + user << "You slide \the [C] into \the [src]." + +/obj/item/device/pda/attack(mob/living/C as mob, mob/living/user as mob) + if (istype(C, /mob/living/carbon) && scanmode) + scanmode.scan_mob(C, user) + +/obj/item/device/pda/afterattack(atom/A as mob|obj|turf|area, mob/user as mob, proximity) + if(proximity && scanmode) + scanmode.scan_atom(A, user) + +/obj/item/device/pda/proc/explode() //This needs tuning. + if(!src.detonate) return + var/turf/T = get_turf(src.loc) + + if (ismob(loc)) + var/mob/M = loc + M.show_message("Your [src] explodes!", 1) + + if(T) + T.hotspot_expose(700,125) + + explosion(T, -1, -1, 2, 3) + qdel(src) + return + +/obj/item/device/pda/Destroy() + PDAs -= src + var/T = get_turf(loc) + if (id) + id.forceMove(T) + if(pai) + pai.forceMove(T) + current_app = null + scanmode = null + for(var/A in programs) + qdel(A) + programs.Cut() + if(cartridge) + cartridge.forceMove(T) + return ..() + +// Pass along the pulse to atoms in contents, largely added so pAIs are vulnerable to EMP +/obj/item/device/pda/emp_act(severity) + for(var/atom/A in src) + A.emp_act(severity) \ No newline at end of file diff --git a/code/modules/pda/ai.dm b/code/modules/pda/ai.dm new file mode 100644 index 00000000000..a6c7769ab52 --- /dev/null +++ b/code/modules/pda/ai.dm @@ -0,0 +1,91 @@ +// Special AI/pAI PDAs that cannot explode. +/obj/item/device/pda/ai + icon_state = "NONE" + detonate = 0 + ttone = "data" + +/obj/item/device/pda/ai/proc/set_name_and_job(newname as text, newjob as text, newrank as null|text) + owner = newname + ownjob = newjob + if(newrank) + ownrank = newrank + else + ownrank = ownjob + name = newname + " (" + ownjob + ")" + +/obj/item/device/pda/ai/verb/cmd_send_pdamesg() + set category = "AI IM" + set name = "Send PDA Message" + set src in usr + + if(usr.stat == DEAD) + usr << "You can't send PDA messages because you are dead!" + return + var/datum/data/pda/app/messenger/M = find_program(/datum/data/pda/app/messenger) + if(!M) + usr << "Cannot use messenger!" + var/list/plist = M.available_pdas() + if (plist) + var/c = input(usr, "Please select a PDA") as null|anything in sortList(plist) + if (!c) // if the user hasn't selected a PDA file we can't send a message + return + var/selected = plist[c] + M.create_message(usr, selected) + +/obj/item/device/pda/ai/verb/cmd_show_message_log() + set category = "AI IM" + set name = "Show Message Log" + set src in usr + + if(usr.stat == DEAD) + usr << "You can't do that because you are dead!" + return + var/datum/data/pda/app/messenger/M = find_program(/datum/data/pda/app/messenger) + if(!M) + usr << "Cannot use messenger!" + var/HTML = "AI PDA Message Log" + for(var/index in M.tnote) + if(index["sent"]) + HTML += addtext("→ To ", index["owner"],":
", index["message"], "
") + else + HTML += addtext("← From ", index["owner"],":
", index["message"], "
") + HTML +="" + usr << browse(HTML, "window=log;size=400x444;border=1;can_resize=1;can_close=1;can_minimize=0") + +/obj/item/device/pda/ai/verb/cmd_toggle_pda_receiver() + set category = "AI IM" + set name = "Toggle Sender/Receiver" + set src in usr + + if(usr.stat == DEAD) + usr << "You can't do that because you are dead!" + return + var/datum/data/pda/app/messenger/M = find_program(/datum/data/pda/app/messenger) + M.toff = !M.toff + usr << "PDA sender/receiver toggled [(M.toff ? "Off" : "On")]!" + + +/obj/item/device/pda/ai/verb/cmd_toggle_pda_silent() + set category = "AI IM" + set name = "Toggle Ringer" + set src in usr + + if(usr.stat == DEAD) + usr << "You can't do that because you are dead!" + return + var/datum/data/pda/app/messenger/M = find_program(/datum/data/pda/app/messenger) + M.silent = !M.silent + usr << "PDA ringer toggled [(M.silent ? "Off" : "On")]!" + +/obj/item/device/pda/ai/can_use() + return 1 + + +/obj/item/device/pda/ai/attack_self(mob/user as mob) + if ((honkamt > 0) && (prob(60)))//For clown virus. + honkamt-- + playsound(loc, 'sound/items/bikehorn.ogg', 30, 1) + return + +/obj/item/device/pda/ai/pai + ttone = "assist" \ No newline at end of file diff --git a/code/modules/pda/app.dm b/code/modules/pda/app.dm new file mode 100644 index 00000000000..1f8b37d97fa --- /dev/null +++ b/code/modules/pda/app.dm @@ -0,0 +1,66 @@ +// Base class for anything that can show up on home screen +/datum/data/pda + var/icon = "tasks" + var/hidden = 0 // program not displayed in main menu + var/category = "General" // the category to list it in on the main menu + var/obj/item/device/pda/pda // if this is null, and the app is running code, something's gone wrong + +/datum/data/pda/Destroy() + pda = null + return ..() + +/datum/data/pda/proc/start() + + +// An app has a button on the home screen and its own UI +/datum/data/pda/app + name = "App" + size = 3 + var/title = null // what is displayed in the title bar when this is the current app + var/template = "" + var/update = PDA_APP_UPDATE + var/has_back = 0 + +/datum/data/pda/app/New() + if(!title) + title = name + +/datum/data/pda/app/start() + pda.current_app = src + return 1 + +/datum/data/pda/app/proc/update_ui(mob/user as mob, list/data) + + +// Utilities just have a button on the home screen, but custom code when clicked +/datum/data/pda/utility + name = "Utility" + icon = "gear" + size = 1 + category = "Utilities" + + +/datum/data/pda/utility/scanmode + var/base_name + category = "Scanners" + +/datum/data/pda/utility/scanmode/New(obj/item/weapon/cartridge/C) + ..(C) + name = "Enable [base_name]" + +/datum/data/pda/utility/scanmode/start() + if(pda.scanmode) + pda.scanmode.name = "Enable [pda.scanmode.base_name]" + + if(pda.scanmode == src) + pda.scanmode = null + else + pda.scanmode = src + name = "Disable [base_name]" + + pda.update_shortcuts() + return 1 + +/datum/data/pda/utility/scanmode/proc/scan_mob(mob/living/C as mob, mob/living/user as mob) + +/datum/data/pda/utility/scanmode/proc/scan_atom(atom/A as mob|obj|turf|area, mob/user as mob) \ No newline at end of file diff --git a/code/modules/pda/cart.dm b/code/modules/pda/cart.dm new file mode 100644 index 00000000000..c96a8cfb11c --- /dev/null +++ b/code/modules/pda/cart.dm @@ -0,0 +1,314 @@ +/obj/item/weapon/cartridge + name = "generic cartridge" + desc = "A data cartridge for portable microcomputers." + icon = 'icons/obj/pda.dmi' + icon_state = "cart" + item_state = "electronic" + w_class = 1 + + var/obj/item/radio/integrated/radio = null + + var/charges = 0 + + var/list/stored_data = list() + var/list/programs = list() + var/list/messenger_plugins = list() + +/obj/item/weapon/cartridge/New() + if(ticker && ticker.current_state >= GAME_STATE_SETTING_UP) + initialize() + +/obj/item/weapon/cartridge/initialize() + if(radio) + radio.initialize() + ..() + +/obj/item/weapon/cartridge/Destroy() + if(radio) + qdel(radio) + radio = null + for(var/A in programs) + qdel(A) + programs.Cut() + for(var/A in messenger_plugins) + qdel(A) + messenger_plugins.Cut() + return ..() + +/obj/item/weapon/cartridge/proc/update_programs(obj/item/device/pda/pda) + for(var/A in programs) + var/datum/data/pda/P = A + P.pda = pda + for(var/A in messenger_plugins) + var/datum/data/pda/messenger_plugin/P = A + P.pda = pda + +/obj/item/weapon/cartridge/engineering + name = "Power-ON Cartridge" + icon_state = "cart-e" + programs = list( + new/datum/data/pda/app/power, + new/datum/data/pda/utility/scanmode/halogen) + +/obj/item/weapon/cartridge/atmos + name = "BreatheDeep Cartridge" + icon_state = "cart-a" + programs = list( + new/datum/data/pda/utility/scanmode/gas) + +/obj/item/weapon/cartridge/medical + name = "Med-U Cartridge" + icon_state = "cart-m" + programs = list( + new/datum/data/pda/app/crew_records/medical, + new/datum/data/pda/utility/scanmode/medical) + +/obj/item/weapon/cartridge/chemistry + name = "ChemWhiz Cartridge" + icon_state = "cart-chem" + programs = list( + new/datum/data/pda/utility/scanmode/reagent) + +/obj/item/weapon/cartridge/security + name = "R.O.B.U.S.T. Cartridge" + icon_state = "cart-s" + programs = list( + new/datum/data/pda/app/crew_records/security, + new/datum/data/pda/app/secbot_control) + +/obj/item/weapon/cartridge/security/initialize() + radio = new /obj/item/radio/integrated/beepsky(src) + ..() + +/obj/item/weapon/cartridge/detective + name = "D.E.T.E.C.T. Cartridge" + icon_state = "cart-s" + programs = list( + new/datum/data/pda/app/crew_records/medical, + new/datum/data/pda/utility/scanmode/medical, + + new/datum/data/pda/app/crew_records/security) + + +/obj/item/weapon/cartridge/janitor + name = "CustodiPRO Cartridge" + desc = "The ultimate in clean-room design." + icon_state = "cart-j" + programs = list( + new/datum/data/pda/app/janitor) + +/obj/item/weapon/cartridge/lawyer + name = "P.R.O.V.E. Cartridge" + icon_state = "cart-s" + programs = list( + new/datum/data/pda/app/crew_records/security) + +/obj/item/weapon/cartridge/clown + name = "Honkworks 5.0" + icon_state = "cart-clown" + charges = 5 + programs = list( + new/datum/data/pda/utility/honk) + messenger_plugins = list( + new/datum/data/pda/messenger_plugin/virus/clown) + +/obj/item/weapon/cartridge/mime + name = "Gestur-O 1000" + icon_state = "cart-mi" + charges = 5 + messenger_plugins = list( + new/datum/data/pda/messenger_plugin/virus/mime) + +/* +/obj/item/weapon/cartridge/botanist + name = "Green Thumb v4.20" + icon_state = "cart-b" + access_flora = 1 +*/ + +/obj/item/weapon/cartridge/signal + name = "generic signaler cartridge" + desc = "A data cartridge with an integrated radio signaler module." + programs = list( + new/datum/data/pda/app/signaller) + +/obj/item/weapon/cartridge/signal/initialize() + radio = new /obj/item/radio/integrated/signal(src) + ..() + +/obj/item/weapon/cartridge/signal/toxins + name = "Signal Ace 2" + desc = "Complete with integrated radio signaler!" + icon_state = "cart-tox" + programs = list( + new/datum/data/pda/utility/scanmode/gas, + + new/datum/data/pda/utility/scanmode/reagent, + + new/datum/data/pda/app/signaller) + +/obj/item/weapon/cartridge/quartermaster + name = "Space Parts & Space Vendors Cartridge" + desc = "Perfect for the Quartermaster on the go!" + icon_state = "cart-q" + programs = list( + new/datum/data/pda/app/supply, + new/datum/data/pda/app/mule_control) + +/obj/item/weapon/cartridge/quartermaster/initialize() + radio = new /obj/item/radio/integrated/mule(src) + ..() + +/obj/item/weapon/cartridge/head + name = "Easy-Record DELUXE" + icon_state = "cart-h" + programs = list( + new/datum/data/pda/app/status_display) + +/obj/item/weapon/cartridge/hop + name = "HumanResources9001" + icon_state = "cart-h" + programs = list( + new/datum/data/pda/app/crew_records/security, + + new/datum/data/pda/app/janitor, + + new/datum/data/pda/app/supply, + new/datum/data/pda/app/mule_control, + + new/datum/data/pda/app/status_display) + +/obj/item/weapon/cartridge/hop/initialize() + radio = new /obj/item/radio/integrated/mule(src) + ..() + +/obj/item/weapon/cartridge/hos + name = "R.O.B.U.S.T. DELUXE" + icon_state = "cart-hos" + programs = list( + new/datum/data/pda/app/crew_records/security, + new/datum/data/pda/app/secbot_control, + + new/datum/data/pda/app/status_display) + +/obj/item/weapon/cartridge/hos/initialize() + radio = new /obj/item/radio/integrated/beepsky(src) + ..() + +/obj/item/weapon/cartridge/ce + name = "Power-On DELUXE" + icon_state = "cart-ce" + programs = list( + new/datum/data/pda/app/power, + new/datum/data/pda/utility/scanmode/halogen, + + new/datum/data/pda/utility/scanmode/gas, + + new/datum/data/pda/app/status_display) + +/obj/item/weapon/cartridge/cmo + name = "Med-U DELUXE" + icon_state = "cart-cmo" + programs = list( + new/datum/data/pda/app/crew_records/medical, + new/datum/data/pda/utility/scanmode/medical, + + new/datum/data/pda/utility/scanmode/reagent, + + new/datum/data/pda/app/status_display) + +/obj/item/weapon/cartridge/rd + name = "Signal Ace DELUXE" + icon_state = "cart-rd" + programs = list( + new/datum/data/pda/utility/scanmode/gas, + + new/datum/data/pda/utility/scanmode/reagent, + + new/datum/data/pda/app/signaller, + + new/datum/data/pda/app/status_display) + +/obj/item/weapon/cartridge/rd/initialize() + radio = new /obj/item/radio/integrated/signal(src) + ..() + +/obj/item/weapon/cartridge/captain + name = "Value-PAK Cartridge" + desc = "Now with 200% more value!" + icon_state = "cart-c" + programs = list( + new/datum/data/pda/app/power, + new/datum/data/pda/utility/scanmode/halogen, + + new/datum/data/pda/utility/scanmode/gas, + + new/datum/data/pda/app/crew_records/medical, + new/datum/data/pda/utility/scanmode/medical, + + new/datum/data/pda/utility/scanmode/reagent, + + new/datum/data/pda/app/crew_records/security, + new/datum/data/pda/app/secbot_control, + + new/datum/data/pda/app/janitor, + + new/datum/data/pda/app/supply, + + new/datum/data/pda/app/status_display) + +/obj/item/weapon/cartridge/captain/initialize() + radio = new /obj/item/radio/integrated/beepsky(src) + ..() + +/obj/item/weapon/cartridge/supervisor + name = "Easy-Record DELUXE" + icon_state = "cart-h" + programs = list( + new/datum/data/pda/app/crew_records/security, + + new/datum/data/pda/app/status_display) + +/obj/item/weapon/cartridge/centcom + name = "Value-PAK Cartridge" + desc = "Now with 200% more value!" + icon_state = "cart-c" + programs = list( + new/datum/data/pda/app/power, + new/datum/data/pda/utility/scanmode/halogen, + + new/datum/data/pda/utility/scanmode/gas, + + new/datum/data/pda/app/crew_records/medical, + new/datum/data/pda/utility/scanmode/medical, + + new/datum/data/pda/utility/scanmode/reagent, + + new/datum/data/pda/app/crew_records/security, + new/datum/data/pda/app/secbot_control, + + new/datum/data/pda/app/janitor, + + new/datum/data/pda/app/supply, + new/datum/data/pda/app/mule_control, + + new/datum/data/pda/app/status_display) + +/obj/item/weapon/cartridge/centcom/initialize() + radio = new /obj/item/radio/integrated/beepsky(src) + ..() + +/obj/item/weapon/cartridge/syndicate + name = "Detomatix Cartridge" + icon_state = "cart" + var/initial_remote_door_id = "smindicate" //Make sure this matches the syndicate shuttle's shield/door id!! //don't ask about the name, testing. + charges = 4 + programs = list( + new/datum/data/pda/utility/toggle_door) + messenger_plugins = list( + new/datum/data/pda/messenger_plugin/virus/detonate) + +/obj/item/weapon/cartridge/syndicate/New() + var/datum/data/pda/utility/toggle_door/D = programs[1] + if(istype(D)) + D.remote_door_id = initial_remote_door_id \ No newline at end of file diff --git a/code/modules/pda/cart_apps.dm b/code/modules/pda/cart_apps.dm new file mode 100644 index 00000000000..0b81365f7d6 --- /dev/null +++ b/code/modules/pda/cart_apps.dm @@ -0,0 +1,420 @@ +/datum/data/pda/app/status_display + name = "Status Display" + icon = "list-alt" + template = "pda_status_display" + category = "Utilities" + + var/message1 // used for status_displays + var/message2 + +/datum/data/pda/app/status_display/update_ui(mob/user as mob, list/data) + data["records"] = list( + "message1" = message1 ? message1 : "(none)", + "message2" = message2 ? message2 : "(none)") + +/datum/data/pda/app/status_display/Topic(href, list/href_list) + switch(href_list["choice"]) + if("Status") + switch(href_list["statdisp"]) + if("message") + post_status("message", message1, message2) + if("alert") + post_status("alert", href_list["alert"]) + if("setmsg1") + message1 = input("Line 1", "Enter Message Text", message1) as text|null + if("setmsg2") + message2 = input("Line 2", "Enter Message Text", message2) as text|null + else + post_status(href_list["statdisp"]) + +/datum/data/pda/app/status_display/proc/post_status(var/command, var/data1, var/data2) + var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435) + if(!frequency) + return + + var/datum/signal/status_signal = new + status_signal.source = src + status_signal.transmission_method = 1 + status_signal.data["command"] = command + + switch(command) + if("message") + status_signal.data["msg1"] = data1 + status_signal.data["msg2"] = data2 + var/mob/user = pda.fingerprintslast + if(istype(pda.loc, /mob/living)) + name = pda.loc + log_admin("STATUS: [user] set status screen with [pda]. Message: [data1] [data2]") + message_admins("STATUS: [user] set status screen with [pda]. Message: [data1] [data2]") + + if("alert") + status_signal.data["picture_state"] = data1 + + spawn(0) + frequency.post_signal(src, status_signal) + + +/datum/data/pda/app/signaller + name = "Signaler System" + icon = "rss" + template = "pda_signaller" + category = "Utilities" + +/datum/data/pda/app/signaller/update_ui(mob/user as mob, list/data) + if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/radio/integrated/signal)) + var/obj/item/radio/integrated/signal/R = pda.cartridge.radio + data["signal_freq"] = format_frequency(R.frequency) + data["signal_code"] = R.code + +/datum/data/pda/app/signaller/Topic(href, list/href_list) + if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/radio/integrated/signal)) + var/obj/item/radio/integrated/signal/R = pda.cartridge.radio + + switch(href_list["choice"]) + if("Send Signal") + spawn(0) + R.send_signal("ACTIVATE") + + if("Signal Frequency") + var/new_frequency = sanitize_frequency(R.frequency + text2num(href_list["sfreq"])) + R.set_frequency(new_frequency) + + if("Signal Code") + R.code += text2num(href_list["scode"]) + R.code = round(R.code) + R.code = min(100, R.code) + R.code = max(1, R.code) + +/datum/data/pda/app/power + name = "Power Monitor" + icon = "exclamation-triangle" + template = "pda_power" + category = "Engineering" + update = PDA_APP_UPDATE_SLOW + + var/obj/machinery/computer/monitor/powmonitor = null + +/datum/data/pda/app/power/update_ui(mob/user as mob, list/data) + update = PDA_APP_UPDATE_SLOW + + if (powmonitor && !isnull(powmonitor.powernet)) + data["records"] = list( + "powerconnected" = 1, + "poweravail" = powmonitor.powernet.avail, + "powerload" = num2text(powmonitor.powernet.viewload, 10), + "powerdemand" = powmonitor.powernet.load, + "apcs" = apc_repository.apc_data(powmonitor)) + has_back = 1 + else + data["records"] = list( + "powerconnected" = 0, + "powermonitors" = powermonitor_repository.powermonitor_data()) + has_back = 0 + +/datum/data/pda/app/power/Topic(href, list/href_list) + switch(href_list["choice"]) + if("Power Select") + var/pref = href_list["target"] + powmonitor = locate(pref) + update = PDA_APP_UPDATE + if("Back") + powmonitor = null + update = PDA_APP_UPDATE + +/datum/data/pda/app/crew_records + var/datum/data/record/general_records = null + +/datum/data/pda/app/crew_records/update_ui(mob/user as mob, list/data) + var/list/records[0] + + if(general_records && general_records in data_core.general) + data["records"] = records + records["general"] = general_records.fields + return records + else + for(var/A in sortRecord(data_core.general)) + var/datum/data/record/R = A + records += list(list(Name = R.fields["name"], "ref" = "\ref[R]")) + data["recordsList"] = records + return null + +/datum/data/pda/app/crew_records/Topic(href, list/href_list) + switch(href_list["choice"]) + if("Records") + var/datum/data/record/R = locate(href_list["target"]) + if (R in data_core.general) + load_records(R) + if("Back") + general_records = null + has_back = 0 + +/datum/data/pda/app/crew_records/proc/load_records(datum/data/record/R) + general_records = R + has_back = 1 + +/datum/data/pda/app/crew_records/medical + name = "Medical Records" + icon = "heartbeat" + template = "pda_medical" + category = "Medical" + + var/datum/data/record/medical_records = null + +/datum/data/pda/app/crew_records/medical/update_ui(mob/user as mob, list/data) + var/list/records = ..() + if(!records) + return + + if(medical_records && medical_records in data_core.medical) + records["medical"] = medical_records.fields + + return records + +/datum/data/pda/app/crew_records/medical/load_records(datum/data/record/R) + ..(R) + for(var/A in data_core.medical) + var/datum/data/record/E = A + if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) + medical_records = E + break + +/datum/data/pda/app/crew_records/security + name = "Security Records" + icon = "tags" + template = "pda_security" + category = "Security" + + var/datum/data/record/security_records = null + +/datum/data/pda/app/crew_records/security/update_ui(mob/user as mob, list/data) + var/list/records = ..() + if(!records) + return + + if(security_records && security_records in data_core.security) + records["security"] = security_records.fields + + return records + +/datum/data/pda/app/crew_records/security/load_records(datum/data/record/R) + ..(R) + for(var/A in data_core.security) + var/datum/data/record/E = A + if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) + security_records = E + break + +/datum/data/pda/app/secbot_control + name = "Security Bot Access" + icon = "rss" + template = "pda_secbot" + category = "Security" + +/datum/data/pda/app/secbot_control/update_ui(mob/user as mob, list/data) + var/botsData[0] + var/beepskyData[0] + if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/radio/integrated/beepsky)) + var/obj/item/radio/integrated/beepsky/SC = pda.cartridge.radio + beepskyData["active"] = SC.active ? sanitize(SC.active.name) : null + has_back = SC.active ? 1 : 0 + if(SC.active && !isnull(SC.botstatus)) + var/area/loca = SC.botstatus["loca"] + var/loca_name = sanitize(loca.name) + beepskyData["botstatus"] = list("loca" = loca_name, "mode" = SC.botstatus["mode"]) + else + beepskyData["botstatus"] = list("loca" = null, "mode" = -1) + var/botsCount=0 + if(SC.botlist && SC.botlist.len) + for(var/obj/machinery/bot/B in SC.botlist) + botsCount++ + if(B.loc) + botsData[++botsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "ref" = "\ref[B]") + + if(!botsData.len) + botsData[++botsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) + + beepskyData["bots"] = botsData + beepskyData["count"] = botsCount + + else + beepskyData["active"] = 0 + botsData[++botsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) + beepskyData["botstatus"] = list("loca" = null, "mode" = null) + beepskyData["bots"] = botsData + beepskyData["count"] = 0 + has_back = 0 + + data["beepsky"] = beepskyData + +/datum/data/pda/app/secbot_control/Topic(href, list/href_list) + switch(href_list["choice"]) + if("Back") + if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/radio/integrated/beepsky)) + pda.cartridge.radio.Topic(null, list(radiomenu = "1", op = "botlist")) + +/datum/data/pda/app/mule_control + name = "Delivery Bot Control" + icon = "truck" + template = "pda_mule" + category = "Quartermaster" + +/datum/data/pda/app/mule_control/update_ui(mob/user as mob, list/data) + var/muleData[0] + var/mulebotsData[0] + if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/radio/integrated/mule)) + var/obj/item/radio/integrated/mule/QC = pda.cartridge.radio + muleData["active"] = QC.active ? sanitize(QC.active.name) : null + has_back = QC.active ? 1 : 0 + if(QC.active && !isnull(QC.botstatus)) + var/area/loca = QC.botstatus["loca"] + var/loca_name = sanitize(loca.name) + muleData["botstatus"] = list("loca" = loca_name, "mode" = QC.botstatus["mode"],"home"=QC.botstatus["home"],"powr" = QC.botstatus["powr"],"retn" =QC.botstatus["retn"], "pick"=QC.botstatus["pick"], "load" = QC.botstatus["load"], "dest" = sanitize(QC.botstatus["dest"])) + + else + muleData["botstatus"] = list("loca" = null, "mode" = -1,"home"=null,"powr" = null,"retn" =null, "pick"=null, "load" = null, "dest" = null) + + + var/mulebotsCount=0 + for(var/obj/machinery/bot/B in QC.botlist) + mulebotsCount++ + if(B.loc) + mulebotsData[++mulebotsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "ref" = "\ref[B]") + + if(!mulebotsData.len) + mulebotsData[++mulebotsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) + + muleData["bots"] = mulebotsData + muleData["count"] = mulebotsCount + + else + muleData["botstatus"] = list("loca" = null, "mode" = -1,"home"=null,"powr" = null,"retn" =null, "pick"=null, "load" = null, "dest" = null) + muleData["active"] = 0 + mulebotsData[++mulebotsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null) + muleData["bots"] = mulebotsData + muleData["count"] = 0 + has_back = 0 + + data["mulebot"] = muleData + +/datum/data/pda/app/mule_control/Topic(href, list/href_list) + switch(href_list["choice"]) + if("Back") + if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/radio/integrated/mule)) + pda.cartridge.radio.Topic(null, list(radiomenu = "1", op = "botlist")) + +/datum/data/pda/app/supply + name = "Supply Records" + icon = "file-text-o" + template = "pda_supply" + category = "Quartermaster" + update = PDA_APP_UPDATE_SLOW + +/datum/data/pda/app/supply/update_ui(mob/user as mob, list/data) + var/supplyData[0] + + if(shuttle_master.supply.mode == SHUTTLE_CALL) + supplyData["shuttle_moving"] = 1 + + if(shuttle_master.supply.z != ZLEVEL_STATION) + supplyData["shuttle_loc"] = "station" + else + supplyData["shuttle_loc"] = "centcom" + + supplyData["shuttle_time"] = "([shuttle_master.supply.timeLeft(600)] Mins)" + + var/supplyOrderCount = 0 + var/supplyOrderData[0] + for(var/S in shuttle_master.shoppinglist) + var/datum/supply_order/SO = S + supplyOrderCount++ + supplyOrderData[++supplyOrderData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "ApprovedBy" = SO.orderedby, "Comment" = html_encode(SO.comment)) + + if(!supplyOrderData.len) + supplyOrderData[++supplyOrderData.len] = list("Number" = null, "Name" = null, "OrderedBy"=null) + + supplyData["approved"] = supplyOrderData + supplyData["approved_count"] = supplyOrderCount + + var/requestCount = 0 + var/requestData[0] + for(var/S in shuttle_master.requestlist) + var/datum/supply_order/SO = S + requestCount++ + requestData[++requestData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "OrderedBy" = SO.orderedby, "Comment" = html_encode(SO.comment)) + + if(!requestData.len) + requestData[++requestData.len] = list("Number" = null, "Name" = null, "orderedBy" = null, "Comment" = null) + + supplyData["requests"] = requestData + supplyData["requests_count"] = requestCount + + data["supply"] = supplyData + +/datum/data/pda/app/janitor + name = "Custodial Locator" + icon = "trash-o" + template = "pda_janitor" + category = "Utilities" + update = PDA_APP_UPDATE_SLOW + +/datum/data/pda/app/janitor/update_ui(mob/user as mob, list/data) + var/JaniData[0] + var/turf/cl = get_turf(pda) + + if(cl) + JaniData["user_loc"] = list("x" = cl.x, "y" = cl.y) + else + JaniData["user_loc"] = list("x" = 0, "y" = 0) + var/MopData[0] + for(var/obj/item/weapon/mop/M in janitorial_equipment) + var/turf/ml = get_turf(M) + if(ml) + if(ml.z != cl.z) + continue + var/direction = get_dir(pda, M) + MopData[++MopData.len] = list ("x" = ml.x, "y" = ml.y, "dir" = uppertext(dir2text(direction)), "status" = M.reagents.total_volume ? "Wet" : "Dry") + + if(!MopData.len) + MopData[++MopData.len] = list("x" = 0, "y" = 0, dir=null, status = null) + + + var/BucketData[0] + for(var/obj/structure/mopbucket/B in janitorial_equipment) + var/turf/bl = get_turf(B) + if(bl) + if(bl.z != cl.z) + continue + var/direction = get_dir(pda,B) + BucketData[++BucketData.len] = list ("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.reagents.total_volume/100) + + if(!BucketData.len) + BucketData[++BucketData.len] = list("x" = 0, "y" = 0, dir=null, status = null) + + var/CbotData[0] + for(var/obj/machinery/bot/cleanbot/B in aibots) + var/turf/bl = get_turf(B) + if(bl) + if(bl.z != cl.z) + continue + var/direction = get_dir(pda,B) + CbotData[++CbotData.len] = list("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.on ? "Online" : "Offline") + + + if(!CbotData.len) + CbotData[++CbotData.len] = list("x" = 0, "y" = 0, dir=null, status = null) + var/CartData[0] + for(var/obj/structure/janitorialcart/B in janitorial_equipment) + var/turf/bl = get_turf(B) + if(bl) + if(bl.z != cl.z) + continue + var/direction = get_dir(pda,B) + CartData[++CartData.len] = list("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.reagents.total_volume/100) + if(!CartData.len) + CartData[++CartData.len] = list("x" = 0, "y" = 0, dir=null, status = null) + + JaniData["mops"] = MopData + JaniData["buckets"] = BucketData + JaniData["cleanbots"] = CbotData + JaniData["carts"] = CartData + data["janitor"] = JaniData \ No newline at end of file diff --git a/code/game/objects/items/devices/PDA/chatroom.dm b/code/modules/pda/chatroom.dm similarity index 100% rename from code/game/objects/items/devices/PDA/chatroom.dm rename to code/modules/pda/chatroom.dm diff --git a/code/modules/pda/core_apps.dm b/code/modules/pda/core_apps.dm new file mode 100644 index 00000000000..55a6dbd6f45 --- /dev/null +++ b/code/modules/pda/core_apps.dm @@ -0,0 +1,106 @@ +/datum/data/pda/app/main_menu + icon = "home" + template = "pda_main_menu" + hidden = 1 + +/datum/data/pda/app/main_menu/update_ui(mob/user as mob, list/data) + title = pda.name + + data["app"]["is_home"] = 1 + + data["apps"] = pda.shortcut_cache + data["categories"] = pda.shortcut_cat_order + data["pai"] = !isnull(pda.pai) // pAI inserted? + +/datum/data/pda/app/main_menu/Topic(href, list/href_list) + switch(href_list["choice"]) + if("UpdateInfo") + pda.ownjob = pda.id.assignment + pda.ownrank = pda.id.rank + pda.name = "PDA-[pda.owner] ([pda.ownjob])" + if("pai") + if(pda.pai) + if(pda.pai.loc != pda) + pda.pai = null + else + switch(href_list["option"]) + if("1") // Configure pAI device + pda.pai.attack_self(usr) + if("2") // Eject pAI device + var/turf/T = get_turf_or_move(pda.loc) + if(T) + pda.pai.loc = T + pda.pai = null + +/datum/data/pda/app/notekeeper + name = "Notekeeper" + icon = "sticky-note-o" + template = "pda_notekeeper" + + var/note = null + var/notehtml = "" + +/datum/data/pda/app/notekeeper/start() + . = ..() + if(!note) + note = "Congratulations, your station has chosen the [pda.model_name]!" + +/datum/data/pda/app/notekeeper/update_ui(mob/user as mob, list/data) + data["note"] = note // current pda notes + +/datum/data/pda/app/notekeeper/Topic(href, list/href_list) + switch(href_list["choice"]) + if("Edit") + var/n = input("Please enter message", name, notehtml) as message + if(pda.loc == usr) + note = adminscrub(n) + notehtml = html_decode(note) + note = replacetext(note, "\n", "
") + else + pda.close(usr) + +/datum/data/pda/app/manifest + name = "Crew Manifest" + icon = "user" + template = "pda_manifest" + update = PDA_APP_UPDATE_SLOW + +/datum/data/pda/app/manifest/update_ui(mob/user as mob, list/data) + data_core.get_manifest_json() + data["manifest"] = list("__json_cache" = ManifestJSON) + +/datum/data/pda/app/manifest/Topic(href, list/href_list) + +/datum/data/pda/app/atmos_scanner + name = "Atmospheric Scan" + icon = "fire" + template = "pda_atmos_scan" + category = "Utilities" + update = PDA_APP_UPDATE_SLOW + +/datum/data/pda/app/atmos_scanner/update_ui(mob/user as mob, list/data) + var/turf/T = get_turf(user.loc) + if(!isnull(T)) + var/datum/gas_mixture/environment = T.return_air() + + var/pressure = environment.return_pressure() + var/total_moles = environment.total_moles() + + if (total_moles) + var/o2_level = environment.oxygen/total_moles + var/n2_level = environment.nitrogen/total_moles + var/co2_level = environment.carbon_dioxide/total_moles + var/plasma_level = environment.toxins/total_moles + var/unknown_level = 1-(o2_level+n2_level+co2_level+plasma_level) + data["aircontents"] = list(\ + "pressure" = "[round(pressure,0.1)]",\ + "nitrogen" = "[round(n2_level*100,0.1)]",\ + "oxygen" = "[round(o2_level*100,0.1)]",\ + "carbon_dioxide" = "[round(co2_level*100,0.1)]",\ + "plasma" = "[round(plasma_level*100,0.01)]",\ + "other" = "[round(unknown_level, 0.01)]",\ + "temp" = "[round(environment.temperature-T0C,0.1)]",\ + "reading" = 1\ + ) + if(isnull(data["aircontents"])) + data["aircontents"] = list("reading" = 0) \ No newline at end of file diff --git a/code/modules/pda/messenger.dm b/code/modules/pda/messenger.dm new file mode 100644 index 00000000000..a6a66d95420 --- /dev/null +++ b/code/modules/pda/messenger.dm @@ -0,0 +1,271 @@ +/datum/data/pda/app/messenger + name = "Messenger" + icon = "comments-o" + title = "SpaceMessenger V4.0.1" + template = "pda_messenger" + + var/silent = 0 //To beep or not to beep, that is the question + var/toff = 0 //If 1, messenger disabled + var/list/tnote[0] //Current Texts + var/last_text //No text spamming + var/list/ttone_sound = list("beep" = 'sound/machines/twobeep.ogg', + "boom" = 'sound/effects/explosionfar.ogg', + "slip" = 'sound/misc/slip.ogg', + "honk" = 'sound/items/bikehorn.ogg', + "SKREE" = 'sound/voice/shriek1.ogg', + "holy" = 'sound/items/PDA/ambicha4-short.ogg', + "xeno" = 'sound/voice/hiss1.ogg') + + var/m_hidden = 0 // Is the PDA hidden from the PDA list? + var/active_conversation = null // New variable that allows us to only view a single conversation. + var/list/conversations = list() // For keeping up with who we have PDA messsages from. + +/datum/data/pda/app/messenger/start() + . = ..() + set_new(0) + +/datum/data/pda/app/messenger/update_ui(mob/user as mob, list/data) + data["silent"] = silent // does the pda make noise when it receives a message? + data["toff"] = toff // is the messenger function turned off? + data["active_conversation"] = active_conversation // Which conversation are we following right now? + + var/convopdas[0] + var/pdas[0] + var/count = 0 + for(var/A in PDAs) + var/obj/item/device/pda/P = A + var/datum/data/pda/app/messenger/PM = P.find_program(/datum/data/pda/app/messenger) + + if (!P.owner || PM.toff || P == pda || PM.m_hidden) + continue + if(conversations.Find("\ref[P]")) + convopdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "1"))) + else + pdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "0"))) + count++ + + data["convopdas"] = convopdas + data["pdas"] = pdas + data["pda_count"] = count + + data["messagescount"] = tnote.len + data["messages"] = tnote + + has_back = active_conversation + if(active_conversation) + for(var/c in tnote) + if(c["target"] == active_conversation) + data["convo_name"] = sanitize(c["owner"]) + data["convo_job"] = sanitize(c["job"]) + break + + var/list/plugins = list() + if(pda.cartridge) + for(var/A in pda.cartridge.messenger_plugins) + var/datum/data/pda/messenger_plugin/P = A + plugins += list(list(name = P.name, icon = P.icon, ref = "\ref[P]")) + data["plugins"] = plugins + + if(pda.cartridge) + data["charges"] = pda.cartridge.charges ? pda.cartridge.charges : 0 + +/datum/data/pda/app/messenger/Topic(href, list/href_list) + set_new(0) + + switch(href_list["choice"]) + if("Toggle Messenger") + toff = !toff + if("Toggle Ringer")//If viewing texts then erase them, if not then toggle silent status + silent = !silent + if("Clear")//Clears messages + if(href_list["option"] == "All") + tnote.Cut() + conversations.Cut() + if(href_list["option"] == "Convo") + var/new_tnote[0] + for(var/i in tnote) + if(i["target"] != active_conversation) + new_tnote[++new_tnote.len] = i + tnote = new_tnote + conversations.Remove(active_conversation) + + active_conversation = null + if("Ringtone") + var/t = input("Please enter new ringtone", name, pda.ttone) as text + if (in_range(pda, usr) && pda.loc == usr) + if (t) + if(pda.hidden_uplink && pda.hidden_uplink.check_trigger(usr, lowertext(t), lowertext(pda.lock_code))) + usr << "The PDA softly beeps." + pda.close(usr) + else + t = sanitize(copytext(t, 1, 20)) + pda.ttone = t + else + pda.close(usr) + return 0 + if("Message") + var/obj/item/device/pda/P = locate(href_list["target"]) + create_message(usr, P) + if(href_list["target"] in conversations) // Need to make sure the message went through, if not welp. + active_conversation = href_list["target"] + if("Select Conversation") + var/P = href_list["convo"] + for(var/n in conversations) + if(P == n) + active_conversation = P + if("Messenger Plugin") + if(!href_list["target"] || !href_list["plugin"]) + return + + var/obj/item/device/pda/P = locate(href_list["target"]) + if(!P) + usr << "PDA not found." + + var/datum/data/pda/messenger_plugin/plugin = locate(href_list["plugin"]) + if(plugin && plugin in pda.cartridge.messenger_plugins) + plugin.messenger = src + plugin.user_act(usr, P) + if("Back") + active_conversation = null + +/datum/data/pda/app/messenger/proc/set_new(isnew) + if(pda.newmessage == isnew) + return + + if(pda.newmessage) + //To clear message overlays. + pda.overlays.Cut() + pda.newmessage = 0 + + icon = "comments" + pda.update_shortcuts() + else + pda.overlays.Cut() + pda.overlays += image('icons/obj/pda.dmi', "pda-r") + pda.newmessage = 1 + + icon = "comments-o" + pda.update_shortcuts() + +/datum/data/pda/app/messenger/proc/create_message(var/mob/living/U, var/obj/item/device/pda/P) + var/t = input(U, "Please enter message", name, null) as text|null + if(!t) + return + t = sanitize(copytext(t, 1, MAX_MESSAGE_LEN)) + t = readd_quotes(t) + if (!t || !istype(P)) + return + if (!in_range(pda, U) && pda.loc != U) + return + + var/datum/data/pda/app/messenger/PM = P.find_program(/datum/data/pda/app/messenger) + + if (!PM || PM.toff || toff) + return + + if (last_text && world.time < last_text + 5) + return + + if(!pda.can_use()) + return + + last_text = world.time + // check if telecomms I/O route 1459 is stable + //var/telecomms_intact = telecomms_process(P.owner, owner, t) + var/obj/machinery/message_server/useMS = null + if(message_servers) + for(var/A in message_servers) + var/obj/machinery/message_server/MS = A + //PDAs are now dependent on the Message Server. + if(MS.active) + useMS = MS + break + + var/datum/signal/signal = pda.telecomms_process() + + var/useTC = 0 + if(signal) + if(signal.data["done"]) + useTC = 1 + var/turf/pos = get_turf(P) + if(pos.z in signal.data["level"]) + useTC = 2 + //Let's make this barely readable + if(signal.data["compression"] > 0) + t = Gibberish(t, signal.data["compression"] + 50) + + if(useMS && useTC) // only send the message if it's stable + if(useTC != 2) // Does our recipient have a broadcaster on their level? + U << "ERROR: Cannot reach recipient." + return + useMS.send_pda_message("[P.owner]","[pda.owner]","[t]") + tnote.Add(list(list("sent" = 1, "owner" = "[P.owner]", "job" = "[P.ownjob]", "message" = "[t]", "target" = "\ref[P]"))) + PM.tnote.Add(list(list("sent" = 0, "owner" = "[pda.owner]", "job" = "[pda.ownjob]", "message" = "[t]", "target" = "\ref[pda]"))) + pda.investigate_log("PDA Message - [U.key] - [pda.owner] -> [P.owner]: [t]", "pda") + if(!conversations.Find("\ref[P]")) + conversations.Add("\ref[P]") + if(!PM.conversations.Find("\ref[pda]")) + PM.conversations.Add("\ref[pda]") + + PM.play_ringtone() + //Search for holder of the PDA. + var/mob/living/L = null + if(P.loc && isliving(P.loc)) + L = P.loc + //Maybe they are a pAI! + else + L = get(P, /mob/living/silicon) + + + if(L) + L << "\icon[P] Message from [pda.owner] ([pda.ownjob]), \"[t]\" (Reply)" + nanomanager.update_user_uis(L, P) // Update the receiving user's PDA UI so that they can see the new message + + nanomanager.update_user_uis(U, P) // Update the sending user's PDA UI so that they can see the new message + set_new(1) + log_pda("[usr] (PDA: [src.name]) sent \"[t]\" to [P.name]") + else + U << "ERROR: Messaging server is not responding." + +/datum/data/pda/app/messenger/proc/play_ringtone() + if (!silent) + var/S + + if(pda.ttone in ttone_sound) + S = ttone_sound[pda.ttone] + else + S = 'sound/machines/twobeep.ogg' + playsound(pda.loc, S, 50, 1) + for(var/mob/O in hearers(3, pda.loc)) + if(!silent) + O.show_message(text("\icon[pda] *[pda.ttone]*")) + +/datum/data/pda/app/messenger/proc/available_pdas() + var/list/names = list() + var/list/plist = list() + var/list/namecounts = list() + + if (toff) + usr << "Turn on your receiver in order to send messages." + return + + for(var/A in PDAs) + var/obj/item/device/pda/P = A + var/datum/data/pda/app/messenger/PM = P.find_program(/datum/data/pda/app/messenger) + + if(!P.owner || !PM || PM.hidden || P == pda || PM.toff) + continue + + var/name = P.owner + if (name in names) + namecounts[name]++ + name = text("[name] ([namecounts[name]])") + else + names.Add(name) + namecounts[name] = 1 + + plist[text("[name]")] = P + return plist + +/datum/data/pda/app/messenger/proc/can_receive() + return pda.owner && !toff && !hidden \ No newline at end of file diff --git a/code/modules/pda/messenger_plugins.dm b/code/modules/pda/messenger_plugins.dm new file mode 100644 index 00000000000..ed4d330fdba --- /dev/null +++ b/code/modules/pda/messenger_plugins.dm @@ -0,0 +1,69 @@ +/datum/data/pda/messenger_plugin + var/datum/data/pda/app/messenger/messenger + +/datum/data/pda/messenger_plugin/proc/user_act(mob/user as mob, obj/item/device/pda/P) + + +/datum/data/pda/messenger_plugin/virus + name = "*Send Virus*" + +/datum/data/pda/messenger_plugin/virus/user_act(mob/user as mob, obj/item/device/pda/P) + var/datum/data/pda/app/messenger/M = P.find_program(/datum/data/pda/app/messenger) + + if(M && !M.toff && pda.cartridge.charges > 0) + pda.cartridge.charges-- + return 1 + return 0 + + +/datum/data/pda/messenger_plugin/virus/clown + icon = "star" + +/datum/data/pda/messenger_plugin/virus/clown/user_act(mob/user as mob, obj/item/device/pda/P) + . = ..(user, P) + if(.) + user.show_message("Virus sent!", 1) + P.honkamt = (rand(15,20)) + P.ttone = "honk" + + +/datum/data/pda/messenger_plugin/virus/mime + icon = "arrow-circle-down" + +/datum/data/pda/messenger_plugin/virus/mime/user_act(mob/user as mob, obj/item/device/pda/P) + . = ..(user, P) + if(.) + user.show_message("Virus sent!", 1) + var/datum/data/pda/app/messenger/M = P.find_program(/datum/data/pda/app/messenger) + if(M) + M.silent = 1 + P.ttone = "silence" + + +/datum/data/pda/messenger_plugin/virus/detonate + name = "*Detonate*" + icon = "exclamation-circle" + +/datum/data/pda/messenger_plugin/virus/detonate/user_act(mob/user as mob, obj/item/device/pda/P) + . = ..(user, P) + if(.) + var/difficulty = 0 + + if(pda.cartridge) + difficulty += pda.cartridge.programs.len / 2 + else + difficulty += 2 + + if(prob(difficulty * 12) || (pda.hidden_uplink)) + user.show_message("An error flashes on your [pda].", 1) + else if (prob(difficulty * 3)) + user.show_message("Energy feeds back into your [pda]!", 1) + pda.close(user) + pda.explode() + log_admin("[key_name(user)] just attempted to blow up [P] with the Detomatix cartridge but failed, blowing themselves up") + message_admins("[key_name_admin(user)] just attempted to blow up [P] with the Detomatix cartridge but failed, blowing themselves up", 1) + else + user.show_message("Success!", 1) + log_admin("[key_name(user)] just attempted to blow up [P] with the Detomatix cartridge and succeded") + message_admins("[key_name_admin(user)] just attempted to blow up [P] with the Detomatix cartridge and succeded", 1) + P.explode() \ No newline at end of file diff --git a/code/modules/pda/pdas.dm b/code/modules/pda/pdas.dm new file mode 100644 index 00000000000..71e831e206d --- /dev/null +++ b/code/modules/pda/pdas.dm @@ -0,0 +1,193 @@ +/obj/item/device/pda/medical + default_cartridge = /obj/item/weapon/cartridge/medical + icon_state = "pda-medical" + +/obj/item/device/pda/viro + default_cartridge = /obj/item/weapon/cartridge/medical + icon_state = "pda-virology" + +/obj/item/device/pda/engineering + default_cartridge = /obj/item/weapon/cartridge/engineering + icon_state = "pda-engineer" + +/obj/item/device/pda/security + default_cartridge = /obj/item/weapon/cartridge/security + icon_state = "pda-security" + +/obj/item/device/pda/detective + default_cartridge = /obj/item/weapon/cartridge/detective + icon_state = "pda-security" + +/obj/item/device/pda/warden + default_cartridge = /obj/item/weapon/cartridge/security + icon_state = "pda-warden" + +/obj/item/device/pda/janitor + default_cartridge = /obj/item/weapon/cartridge/janitor + icon_state = "pda-janitor" + ttone = "slip" + +/obj/item/device/pda/toxins + default_cartridge = /obj/item/weapon/cartridge/signal/toxins + icon_state = "pda-science" + ttone = "boom" + +/obj/item/device/pda/clown + default_cartridge = /obj/item/weapon/cartridge/clown + icon_state = "pda-clown" + desc = "A portable microcomputer by Thinktronic Systems, LTD. The surface is coated with polytetrafluoroethylene and banana drippings." + ttone = "honk" + +/obj/item/device/pda/clown/Crossed(AM as mob|obj) //Clown PDA is slippery. + if (istype(AM, /mob/living/carbon)) + var/mob/living/carbon/M = AM + M.slip("pda", 8, 5, 0, 1) + +/obj/item/device/pda/mime + default_cartridge = /obj/item/weapon/cartridge/mime + icon_state = "pda-mime" + ttone = "silence" + +/obj/item/device/pda/mime/New() + var/datum/data/pda/app/messenger/M = find_program(/datum/data/pda/app/messenger) + if(M) + M.silent = 1 + +/obj/item/device/pda/heads + default_cartridge = /obj/item/weapon/cartridge/head + icon_state = "pda-h" + +/obj/item/device/pda/heads/hop + default_cartridge = /obj/item/weapon/cartridge/hop + icon_state = "pda-hop" + +/obj/item/device/pda/heads/hos + default_cartridge = /obj/item/weapon/cartridge/hos + icon_state = "pda-hos" + +/obj/item/device/pda/heads/ce + default_cartridge = /obj/item/weapon/cartridge/ce + icon_state = "pda-ce" + +/obj/item/device/pda/heads/cmo + default_cartridge = /obj/item/weapon/cartridge/cmo + icon_state = "pda-cmo" + +/obj/item/device/pda/heads/rd + default_cartridge = /obj/item/weapon/cartridge/rd + icon_state = "pda-rd" + +/obj/item/device/pda/captain + default_cartridge = /obj/item/weapon/cartridge/captain + icon_state = "pda-captain" + detonate = 0 + //toff = 1 + +/obj/item/device/pda/heads/ntrep + default_cartridge = /obj/item/weapon/cartridge/supervisor + icon_state = "pda-h" + +/obj/item/device/pda/heads/magistrate + default_cartridge = /obj/item/weapon/cartridge/supervisor + icon_state = "pda-h" + +/obj/item/device/pda/heads/blueshield + default_cartridge = /obj/item/weapon/cartridge/hos + icon_state = "pda-h" + +/obj/item/device/pda/cargo + default_cartridge = /obj/item/weapon/cartridge/quartermaster + icon_state = "pda-cargo" + +/obj/item/device/pda/quartermaster + default_cartridge = /obj/item/weapon/cartridge/quartermaster + icon_state = "pda-qm" + +/obj/item/device/pda/shaftminer + icon_state = "pda-miner" + +/obj/item/device/pda/syndicate + default_cartridge = /obj/item/weapon/cartridge/syndicate + icon_state = "pda-syndi" + name = "Military PDA" + owner = "John Doe" + +/obj/item/device/pda/syndicate/New() + var/datum/data/pda/app/messenger/M = find_program(/datum/data/pda/app/messenger) + if(M) + M.m_hidden = 1 + +/obj/item/device/pda/chaplain + icon_state = "pda-chaplain" + ttone = "holy" + +/obj/item/device/pda/lawyer + default_cartridge = /obj/item/weapon/cartridge/lawyer + icon_state = "pda-lawyer" + ttone = "..." + +/obj/item/device/pda/botanist + //default_cartridge = /obj/item/weapon/cartridge/botanist + icon_state = "pda-hydro" + +/obj/item/device/pda/roboticist + icon_state = "pda-roboticist" + +/obj/item/device/pda/librarian + icon_state = "pda-library" + desc = "A portable microcomputer by Thinktronic Systems, LTD. This is model is a WGW-11 series e-reader." + model_name = "Thinktronic 5290 WGW-11 Series E-reader and Personal Data Assistant" + +/obj/item/device/pda/librarian/New() + var/datum/data/pda/app/messenger/M = find_program(/datum/data/pda/app/messenger) + if(M) + M.silent = 1 //Quiet in the library! + +/obj/item/device/pda/clear + icon_state = "pda-transp" + desc = "A portable microcomputer by Thinktronic Systems, LTD. This is model is a special edition with a transparent case." + model_name = "Thinktronic 5230 Personal Data Assistant Deluxe Special Max Turbo Limited Edition" + +/obj/item/device/pda/chef + icon_state = "pda-chef" + +/obj/item/device/pda/bar + icon_state = "pda-bartender" + +/obj/item/device/pda/atmos + default_cartridge = /obj/item/weapon/cartridge/atmos + icon_state = "pda-atmos" + +/obj/item/device/pda/chemist + default_cartridge = /obj/item/weapon/cartridge/chemistry + icon_state = "pda-chemistry" + +/obj/item/device/pda/geneticist + default_cartridge = /obj/item/weapon/cartridge/medical + icon_state = "pda-genetics" + +/obj/item/device/pda/centcom + default_cartridge = /obj/item/weapon/cartridge/centcom + icon_state = "pda-h" + +//Some spare PDAs in a box +/obj/item/weapon/storage/box/PDAs + name = "spare PDAs" + desc = "A box of spare PDA microcomputers." + icon = 'icons/obj/pda.dmi' + icon_state = "pdabox" + +/obj/item/weapon/storage/box/PDAs/New() + ..() + new /obj/item/device/pda(src) + new /obj/item/device/pda(src) + new /obj/item/device/pda(src) + new /obj/item/device/pda(src) + new /obj/item/weapon/cartridge/head(src) + + var/newcart = pick( /obj/item/weapon/cartridge/engineering, + /obj/item/weapon/cartridge/security, + /obj/item/weapon/cartridge/medical, + /obj/item/weapon/cartridge/signal/toxins, + /obj/item/weapon/cartridge/quartermaster) + new newcart(src) \ No newline at end of file diff --git a/code/game/objects/items/devices/PDA/radio.dm b/code/modules/pda/radio.dm similarity index 77% rename from code/game/objects/items/devices/PDA/radio.dm rename to code/modules/pda/radio.dm index 3e180a5c700..02a5dc996e2 100644 --- a/code/game/objects/items/devices/PDA/radio.dm +++ b/code/modules/pda/radio.dm @@ -26,6 +26,7 @@ /obj/item/radio/integrated/Destroy() if(radio_controller) radio_controller.remove_object(src, control_freq) + hostpda = null return ..() /obj/item/radio/integrated/proc/post_signal(var/freq, var/key, var/value, var/key2, var/value2, var/key3, var/value3,var/key4, var/value4, s_filter) @@ -49,8 +50,6 @@ frequency.post_signal(src, signal, filter = s_filter) - return - /obj/item/radio/integrated/receive_signal(datum/signal/signal) /*var/obj/item/device/pda/P = src.loc @@ -79,22 +78,26 @@ if("control") active = locate(href_list["bot"]) - post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter) + spawn(0) + post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter) if("scanbots") // find all bots botlist = null - post_signal(control_freq, "command", "bot_status", s_filter = bot_filter) + spawn(0) + post_signal(control_freq, "command", "bot_status", s_filter = bot_filter) if("botlist") active = null if("stop", "go") - post_signal(control_freq, "command", href_list["op"], "active", active, s_filter = bot_filter) - post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter) + spawn(0) + post_signal(control_freq, "command", href_list["op"], "active", active, s_filter = bot_filter) + post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter) if("summon") - post_signal(control_freq, "command", "summon", "active", active, "target", get_turf(PDA) , "useraccess", PDA.GetAccess(), s_filter = bot_filter) - post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter) + spawn(0) + post_signal(control_freq, "command", "summon", "active", active, "target", get_turf(PDA) , "useraccess", PDA.GetAccess(), s_filter = bot_filter) + post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter) /obj/item/radio/integrated/proc/add_to_radio(bot_filter) //Master filter control for bots. Must be placed in the bot's local New() to support map spawned bots. if(radio_controller) @@ -147,13 +150,6 @@ // create/populate lists as they are recvd /obj/item/radio/integrated/mule/receive_signal(datum/signal/signal) -// var/obj/item/device/pda/P = src.loc - - /* - world << "recvd:[P] : [signal.source]" - for(var/d in signal.data) - world << "- [d] = [signal.data[d]]" - */ if(signal.data["type"] == MULE_BOT) if(!botlist) botlist = new() @@ -171,9 +167,6 @@ beacons[signal.data["beacon"] ] = signal.source - -// if(istype(P)) P.updateSelfDialog() - /obj/item/radio/integrated/mule/Topic(href, href_list) //..() //var/obj/item/device/pda/PDA = src.hostpda @@ -182,7 +175,6 @@ cmd = "command [active.suffix]" switch(href_list["op"]) - if("control") active = locate(href_list["bot"]) @@ -193,28 +185,37 @@ active = null if("unload") - post_signal(control_freq, cmd, "unload", s_filter = RADIO_MULEBOT) + spawn(0) + post_signal(control_freq, cmd, "unload", s_filter = RADIO_MULEBOT) if("setdest") if(beacons) var/dest = input("Select Bot Destination", "Mulebot [active.suffix] Interlink", active.destination) as null|anything in beacons if(dest) - post_signal(control_freq, cmd, "target", "destination", dest, s_filter = RADIO_MULEBOT) + spawn(0) + post_signal(control_freq, cmd, "target", "destination", dest, s_filter = RADIO_MULEBOT) if("retoff") - post_signal(control_freq, cmd, "autoret", "value", 0, s_filter = RADIO_MULEBOT) + spawn(0) + post_signal(control_freq, cmd, "autoret", "value", 0, s_filter = RADIO_MULEBOT) + if("reton") - post_signal(control_freq, cmd, "autoret", "value", 1, s_filter = RADIO_MULEBOT) + spawn(0) + post_signal(control_freq, cmd, "autoret", "value", 1, s_filter = RADIO_MULEBOT) if("pickoff") - post_signal(control_freq, cmd, "autopick", "value", 0, s_filter = RADIO_MULEBOT) + spawn(0) + post_signal(control_freq, cmd, "autopick", "value", 0, s_filter = RADIO_MULEBOT) if("pickon") - post_signal(control_freq, cmd, "autopick", "value", 1, s_filter = RADIO_MULEBOT) + spawn(0) + post_signal(control_freq, cmd, "autopick", "value", 1, s_filter = RADIO_MULEBOT) if("stop", "go", "home") - post_signal(control_freq, cmd, href_list["op"], s_filter = RADIO_MULEBOT) + spawn(0) + post_signal(control_freq, cmd, href_list["op"], s_filter = RADIO_MULEBOT) - post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT) + spawn(10) + post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT) @@ -262,6 +263,5 @@ signal.encryption = code signal.data["message"] = message - radio_connection.post_signal(src, signal) - - return \ No newline at end of file + spawn(0) + radio_connection.post_signal(src, signal) \ No newline at end of file diff --git a/code/modules/pda/utilities.dm b/code/modules/pda/utilities.dm new file mode 100644 index 00000000000..f86c234d6f9 --- /dev/null +++ b/code/modules/pda/utilities.dm @@ -0,0 +1,198 @@ +/datum/data/pda/utility/flashlight + name = "Enable Flashlight" + icon = "lightbulb-o" + + var/fon = 0 //Is the flashlight function on? + var/f_lum = 2 //Luminosity for the flashlight function + +/datum/data/pda/utility/flashlight/start() + fon = !fon + name = fon ? "Disable Flashlight" : "Enable Flashlight" + pda.update_shortcuts() + pda.set_light(fon ? f_lum : 0) + +/datum/data/pda/utility/honk + name = "Honk Synthesizer" + icon = "smile-o" + category = "Clown" + + var/last_honk //Also no honk spamming that's bad too + +/datum/data/pda/utility/honk/start() + if(!(last_honk && world.time < last_honk + 20)) + playsound(pda.loc, 'sound/items/bikehorn.ogg', 50, 1) + last_honk = world.time + +/datum/data/pda/utility/toggle_door + name = "Toggle Door" + icon = "external-link" + var/remote_door_id = "" + +/datum/data/pda/utility/toggle_door/start() + for(var/obj/machinery/door/poddoor/M in airlocks) + if(M.id_tag == remote_door_id) + if(M.density) + M.open() + else + M.close() + +/datum/data/pda/utility/scanmode/medical + base_name = "Med Scanner" + icon = "heart-o" + +/datum/data/pda/utility/scanmode/medical/scan_mob(mob/living/C as mob, mob/living/user as mob) + C.visible_message("[user] has analyzed [C]'s vitals!") + + user.show_message("Analyzing Results for [C]:") + user.show_message("\t Overall Status: [C.stat > 1 ? "dead" : "[C.health - C.halloss]% healthy"]", 1) + user.show_message("\t Damage Specifics: [C.getOxyLoss() > 50 ? "" : ""][C.getOxyLoss()]-[C.getToxLoss() > 50 ? "" : ""][C.getToxLoss()]-[C.getFireLoss() > 50 ? "" : ""][C.getFireLoss()]-[C.getBruteLoss() > 50 ? "" : ""][C.getBruteLoss()]", 1) + user.show_message("\t Key: Suffocation/Toxin/Burns/Brute", 1) + user.show_message("\t Body Temperature: [C.bodytemperature-T0C]°C ([C.bodytemperature*1.8-459.67]°F)", 1) + if(C.timeofdeath && (C.stat == DEAD || (C.status_flags & FAKEDEATH))) + user.show_message("\t Time of Death: [C.timeofdeath]") + if(istype(C, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = C + var/list/damaged = H.get_damaged_organs(1,1) + user.show_message("Localized Damage, Brute/Burn:",1) + if(length(damaged)>0) + for(var/obj/item/organ/external/org in damaged) + user.show_message("\t [capitalize(org.name)]: [org.brute_dam > 0 ? "[org.brute_dam]" : "0"]-[org.burn_dam > 0 ? "[org.burn_dam]" : "0"]", 1) + else + user.show_message("\t Limbs are OK.",1) + +/datum/data/pda/utility/scanmode/dna + base_name = "DNA Scanner" + icon = "link" + +/datum/data/pda/utility/scanmode/dna/scan_mob(mob/living/C as mob, mob/living/user as mob) + if(istype(C, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = C + if (!istype(H.dna, /datum/dna)) + user << "No fingerprints found on [H]" + else + user << "[H]'s Fingerprints: [md5(H.dna.uni_identity)]" + scan_blood(C, user) + +/datum/data/pda/utility/scanmode/dna/scan_atom(atom/A as mob|obj|turf|area, mob/user as mob) + scan_blood(A, user) + +/datum/data/pda/utility/scanmode/dna/proc/scan_blood(atom/A, mob/user) + if (!A.blood_DNA) + user << "No blood found on [A]" + if(A.blood_DNA) + qdel(A.blood_DNA) + else + user << "Blood found on [A]. Analysing..." + spawn(15) + for(var/blood in A.blood_DNA) + user << "Blood type: [A.blood_DNA[blood]]\nDNA: [blood]" + +/datum/data/pda/utility/scanmode/halogen + base_name = "Halogen Counter" + icon = "exclamation-circle" + +/datum/data/pda/utility/scanmode/halogen/scan_mob(mob/living/C as mob, mob/living/user as mob) + C.visible_message("[user] has analyzed [C]'s radiation levels!") + + user.show_message("Analyzing Results for [C]:") + if(C.radiation) + user.show_message("Radiation Level: [C.radiation > 0 ? "[C.radiation]" : "0"]") + else + user.show_message("No radiation detected.") + +/datum/data/pda/utility/scanmode/reagent + base_name = "Reagent Scanner" + icon = "flask" + +/datum/data/pda/utility/scanmode/reagent/scan_atom(atom/A as mob|obj|turf|area, mob/user as mob) + if(!isnull(A.reagents)) + if(A.reagents.reagent_list.len > 0) + var/reagents_length = A.reagents.reagent_list.len + user << "[reagents_length] chemical agent[reagents_length > 1 ? "s" : ""] found." + for(var/re in A.reagents.reagent_list) + user << "\t [re]" + else + user << "No active chemical agents found in [A]." + else + user << "No significant chemical agents found in [A]." + +/datum/data/pda/utility/scanmode/gas + base_name = "Gas Scanner" + icon = "tachometer" + +/datum/data/pda/utility/scanmode/gas/scan_atom(atom/A as mob|obj|turf|area, mob/user as mob) + if (istype(A, /obj/item/weapon/tank)) + var/obj/item/weapon/tank/T = A + pda.atmosanalyzer_scan(T.air_contents, user, T) + else if (istype(A, /obj/machinery/portable_atmospherics)) + var/obj/machinery/portable_atmospherics/T = A + pda.atmosanalyzer_scan(T.air_contents, user, T) + else if (istype(A, /obj/machinery/atmospherics/pipe)) + var/obj/machinery/atmospherics/pipe/T = A + pda.atmosanalyzer_scan(T.parent.air, user, T) + else if (istype(A, /obj/machinery/power/rad_collector)) + var/obj/machinery/power/rad_collector/T = A + if(T.P) + pda.atmosanalyzer_scan(T.P.air_contents, user, T) + else if (istype(A, /obj/item/weapon/flamethrower)) + var/obj/item/weapon/flamethrower/T = A + if(T.ptank) + pda.atmosanalyzer_scan(T.ptank.air_contents, user, T) + else if (istype(A, /obj/machinery/portable_atmospherics/scrubber/huge)) + var/obj/machinery/portable_atmospherics/scrubber/huge/T = A + pda.atmosanalyzer_scan(T.air_contents, user, T) + else if (istype(A, /obj/machinery/atmospherics/unary/tank)) + var/obj/machinery/atmospherics/unary/tank/T = A + pda.atmosanalyzer_scan(T.air_contents, user, T) + +/datum/data/pda/utility/scanmode/notes + base_name = "Note Scanner" + icon = "clipboard" + var/datum/data/pda/app/notekeeper/notes + +/datum/data/pda/utility/scanmode/notes/start() + . = ..() + notes = pda.find_program(/datum/data/pda/app/notekeeper) + +/datum/data/pda/utility/scanmode/notes/scan_atom(atom/A as mob|obj|turf|area, mob/user as mob) + if(notes && istype(A, /obj/item/weapon/paper)) + var/obj/item/weapon/paper/P = A + + // JMO 20140705: Makes scanned document show up properly in the notes. Not pretty for formatted documents, + // as this will clobber the HTML, but at least it lets you scan a document. You can restore the original + // notes by editing the note again. (Was going to allow you to edit, but scanned documents are too long.) + var/raw_scan = P.info + var/formatted_scan = "" + // Scrub out the tags (replacing a few formatting ones along the way) + // Find the beginning and end of the first tag. + var/tag_start = findtext(raw_scan, "<") + var/tag_stop = findtext(raw_scan, ">") + // Until we run out of complete tags... + while(tag_start && tag_stop) + var/pre = copytext(raw_scan, 1, tag_start) // Get the stuff that comes before the tag + var/tag = lowertext(copytext(raw_scan, tag_start + 1, tag_stop)) // Get the tag so we can do intellegent replacement + var/tagend = findtext(tag, " ") // Find the first space in the tag if there is one. + // Anything that's before the tag can just be added as is. + formatted_scan = formatted_scan + pre + // If we have a space after the tag (and presumably attributes) just crop that off. + if(tagend) + tag = copytext(tag, 1, tagend) + if(tag == "p" || tag == "/p" || tag == "br") // Check if it's I vertical space tag. + formatted_scan = formatted_scan + "
" // If so, add some padding in. + raw_scan = copytext(raw_scan, tag_stop + 1) // continue on with the stuff after the tag + // Look for the next tag in what's left + tag_start = findtext(raw_scan, "<") + tag_stop = findtext(raw_scan, ">") + // Anything that is left in the page. just tack it on to the end as is + formatted_scan = formatted_scan + raw_scan + // If there is something in there already, pad it out. + if(length(notes.note) > 0) + notes.note = notes.note + "

" + // Store the scanned document to the notes + notes.note = "Scanned Document. Edit to restore previous notes/delete scan.
----------
" + formatted_scan + "
" + // notehtml ISN'T set to allow user to get their old notes back. A better implementation would add a "scanned documents" + // feature to the PDA, which would better convey the availability of the feature, but this will work for now. + // Inform the user + user << "Paper scanned and OCRed to notekeeper." //concept of scanning paper copyright brainoblivion 2009 + else + user << "Error scanning [A]." \ No newline at end of file diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index c1eb0f1ebee..d44fb37f20b 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -19,6 +19,7 @@ throw_range = 5 force = 5.0 origin_tech = "combat=1" + needs_permit = 1 attack_verb = list("struck", "hit", "bashed") var/fire_sound = 'sound/weapons/Gunshot.ogg' diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm index ed4ca6eeeed..1558304b191 100644 --- a/code/modules/projectiles/guns/energy/laser.dm +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -15,6 +15,7 @@ desc = "A modified version of the basic laser gun, this one fires less concentrated energy bolts designed for target practice." projectile_type = "/obj/item/projectile/practice" clumsy_check = 0 + needs_permit = 0 obj/item/weapon/gun/energy/laser/retro name ="retro laser gun" @@ -107,6 +108,7 @@ obj/item/weapon/gun/energy/laser/retro projectile_type = "/obj/item/projectile/lasertag/blue" origin_tech = "combat=1;magnets=2" clumsy_check = 0 + needs_permit = 0 self_recharge = 1 @@ -124,6 +126,7 @@ obj/item/weapon/gun/energy/laser/retro projectile_type = "/obj/item/projectile/lasertag/red" origin_tech = "combat=1;magnets=2" clumsy_check = 0 + needs_permit = 0 self_recharge = 1 diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index 9bb7d479de5..7093eb7202a 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -41,6 +41,7 @@ origin_tech = "materials=2;biotech=3;powerstorage=3" modifystate = "floramut" var/mode = 0 //0 = mutate, 1 = yield boost + needs_permit = 0 self_recharge = 1 @@ -202,6 +203,7 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out. fire_sound = 'sound/weapons/Kenetic_accel.ogg' charge_cost = 5000 cell_type = "/obj/item/weapon/stock_parts/cell/emproof" + needs_permit = 0 // Aparently these are safe to carry? I'm sure Golliaths would disagree. fire_delay = 16 //Because guncode is bad and you can bug the reload for rapid fire otherwise. var/recently_fired = 0 diff --git a/code/modules/reagents/oldchem/reagents/reagents_food.dm b/code/modules/reagents/oldchem/reagents/reagents_food.dm index da3244cbda2..70b8929832d 100644 --- a/code/modules/reagents/oldchem/reagents/reagents_food.dm +++ b/code/modules/reagents/oldchem/reagents/reagents_food.dm @@ -14,7 +14,7 @@ if(!(M.mind in ticker.mode.vampires)) if(ishuman(M)) var/mob/living/carbon/human/H = M - if(H.species && H.species.dietflags) //Make sure the species has it's dietflag set, otherwise it can't digest any nutrients + if(H.can_eat()) //Make sure the species has it's dietflag set, otherwise it can't digest any nutrients H.nutrition += nutriment_factor // For hunger and fatness if(prob(50)) M.heal_organ_damage(1,0) if(istype(M,/mob/living/simple_animal)) //Any nutrients can heal simple animals @@ -36,7 +36,7 @@ if(!(M.mind in ticker.mode.vampires)) if(ishuman(M)) var/mob/living/carbon/human/H = M - if(H.species && H.species.dietflags && !(H.species.dietflags & DIET_HERB)) //Make sure the species has it's dietflag set, and that it is not a herbivore + if(H.can_eat(DIET_CARN | DIET_OMNI)) //Make sure that it is not a herbivore H.nutrition += nutriment_factor // For hunger and fatness if(prob(50)) M.heal_organ_damage(1,0) if(istype(M,/mob/living/simple_animal)) //Any nutrients can heal simple animals @@ -58,7 +58,7 @@ if(!(M.mind in ticker.mode.vampires)) if(ishuman(M)) var/mob/living/carbon/human/H = M - if(H.species && H.species.dietflags && !(H.species.dietflags & DIET_CARN)) //Make sure the species has it's dietflag set, and that it is not a carnivore + if(H.can_eat(DIET_HERB | DIET_OMNI)) //Make sure that it is not a carnivore H.nutrition += nutriment_factor // For hunger and fatness if(prob(50)) M.heal_organ_damage(1,0) if(istype(M,/mob/living/simple_animal)) //Any nutrients can heal simple animals diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm index fb97c2b693c..648193a316b 100644 --- a/code/modules/research/designs/machine_designs.dm +++ b/code/modules/research/designs/machine_designs.dm @@ -490,4 +490,13 @@ build_type = IMPRINTER materials = list(MAT_GLASS=1000, "sacid"=20) build_path = /obj/item/weapon/circuitboard/clawgame - category = list ("Misc. Machinery") \ No newline at end of file + category = list ("Misc. Machinery") + +/datum/design/prize_counter + name = "Machine Design (Prize Counter)" + desc = "The circuit board for an arcade Prize Counter." + req_tech = list("programming" = 2, "materials" = 2) + build_type = IMPRINTER + materials = list(MAT_GLASS=1000, "sacid"=20) + build_path = /obj/item/weapon/circuitboard/prize_counter + category = list("Misc. Machinery") \ No newline at end of file diff --git a/html/changelog.html b/html/changelog.html index 1ee52cfb38c..436cd9f76d4 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -55,6 +55,56 @@ -->
+

13 February 2016

+

Crazylemon64 updated:

+
    +
  • Relaxes the check on what atoms you can follow to any movable atom
  • +
  • Mages are now more ragin
  • +
  • Admins can now adjust the total number of wizards at runtime by tweaking either max_mages, or players_per mage
  • +
+

DaveTheHeadcrab updated:

+
    +
  • Adds new worn icons for duffelbags to better reflect their size, compliments of WJohn at /tg/
  • +
+

FalseIncarnate updated:

+
    +
  • Adds burritos, made from cutlets, beans, rice, capsacin oil (hotsauce), cheese, and flat dough (because we lack proper tortillas) in the microwave.
  • +
  • Adds chimichangas. You know you want a deep-fried burrito.
  • +
+

Fox McCloud updated:

+
    +
  • Updates some spell icons with better/higher quality icons
  • +
  • Updates unarmed attacks to allow for more customization
  • +
  • Updates martial arts so they factor in specie's attack messages and sounds
  • +
  • Re-balances Sleeping Carp fighting style
  • +
  • Re-balances Bo Staff
  • +
  • Rebalances Golem: they should now be spaceproof, fire+cold proof, rad proof, virus immune, clonable, parapen+syringe gun immune, deal increased melee damage. Their armor has been reduced to 55 melee across the board, their slip immunity removed, pain immunity removed, and they're slightly slower
  • +
  • Fixes Ei Nath generating two brains
  • +
  • Ensures the Necromatic Stone generates actual skeletons
  • +
  • Can now strip PDA/IDs from Golems
  • +
  • Fixes sleeping carp grab not being an instant aggressive grab
  • +
  • Fixes an exploit with declaring war on the station
  • +
+

KasparoVy updated:

+
    +
  • Orange and purple bandanas for all station species.
  • +
  • The ability to colour bandanas with a crayon in a washing machine.
  • +
  • Refactors the bandana adjustment system.
  • +
  • Minor adjustments to Tajaran and Unathi bandana east/west sprites.
  • +
  • Adjusting a bandana will now take if off of your head/face and put it in an available hand. If both hands are available, it goes in the selected hand.
  • +
  • Adjusting a coloured bandana will no longer revert it to the original coloured icons anymore.
  • +
  • Adjusting a bandana from mask-style to hat-style means the bandana won't obscure your identity anymore.
  • +
  • Greys now use re-positioned smokeables. They no longer smoke out the eyes.
  • +
+

TheDZD updated:

+
    +
  • Fixes spacepods being able to shoot through walls.
  • +
  • Lowers spacepod weapons fire delay.
  • +
  • Increases spacepod weapons energy costs.
  • +
  • Makes spacepods move at speeds not rivaling those of photon beams. They are now a hair bit faster than a person with a jetpack.
  • +
  • Reduces battery costs for spacepod movement.
  • +
+

10 February 2016

Crazylemon64 updated:

    diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index b296bd4a74f..20d699e2a5b 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -473,3 +473,50 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. - rscadd: Adds shadowling thrall jobbans. - rscadd: Jobbanned players who are converted to shadowling thrall, revolutionary, or cultist will have the control of their body offered up to eligible ghosts. +2016-02-13: + Crazylemon64: + - tweak: Relaxes the check on what atoms you can follow to any movable atom + - tweak: Mages are now more ragin + - tweak: Admins can now adjust the total number of wizards at runtime by tweaking + either max_mages, or players_per mage + DaveTheHeadcrab: + - rscadd: Adds new worn icons for duffelbags to better reflect their size, compliments + of WJohn at /tg/ + FalseIncarnate: + - rscadd: Adds burritos, made from cutlets, beans, rice, capsacin oil (hotsauce), + cheese, and flat dough (because we lack proper tortillas) in the microwave. + - rscadd: Adds chimichangas. You know you want a deep-fried burrito. + Fox McCloud: + - tweak: Updates some spell icons with better/higher quality icons + - tweak: Updates unarmed attacks to allow for more customization + - tweak: Updates martial arts so they factor in specie's attack messages and sounds + - tweak: Re-balances Sleeping Carp fighting style + - tweak: Re-balances Bo Staff + - tweak: 'Rebalances Golem: they should now be spaceproof, fire+cold proof, rad + proof, virus immune, clonable, parapen+syringe gun immune, deal increased melee + damage. Their armor has been reduced to 55 melee across the board, their slip + immunity removed, pain immunity removed, and they''re slightly slower' + - bugfix: Fixes Ei Nath generating two brains + - bugfix: Ensures the Necromatic Stone generates actual skeletons + - bugfix: Can now strip PDA/IDs from Golems + - bugfix: Fixes sleeping carp grab not being an instant aggressive grab + - bugfix: Fixes an exploit with declaring war on the station + KasparoVy: + - rscadd: Orange and purple bandanas for all station species. + - rscadd: The ability to colour bandanas with a crayon in a washing machine. + - tweak: Refactors the bandana adjustment system. + - tweak: Minor adjustments to Tajaran and Unathi bandana east/west sprites. + - tweak: Adjusting a bandana will now take if off of your head/face and put it in + an available hand. If both hands are available, it goes in the selected hand. + - bugfix: Adjusting a coloured bandana will no longer revert it to the original + coloured icons anymore. + - bugfix: Adjusting a bandana from mask-style to hat-style means the bandana won't + obscure your identity anymore. + - rscadd: Greys now use re-positioned smokeables. They no longer smoke out the eyes. + TheDZD: + - bugfix: Fixes spacepods being able to shoot through walls. + - tweak: Lowers spacepod weapons fire delay. + - tweak: Increases spacepod weapons energy costs. + - tweak: Makes spacepods move at speeds not rivaling those of photon beams. They + are now a hair bit faster than a person with a jetpack. + - tweak: Reduces battery costs for spacepod movement. diff --git a/html/changelogs/AutoChangeLog-pr-3547.yml b/html/changelogs/AutoChangeLog-pr-3547.yml deleted file mode 100644 index 8c1f845f0c6..00000000000 --- a/html/changelogs/AutoChangeLog-pr-3547.yml +++ /dev/null @@ -1,10 +0,0 @@ -author: KasparoVy -delete-after: True -changes: - - rscadd: "Orange and purple bandanas for all station species." - - rscadd: "The ability to colour bandanas with a crayon in a washing machine." - - tweak: "Refactors the bandana adjustment system." - - tweak: "Minor adjustments to Tajaran and Unathi bandana east/west sprites." - - tweak: "Adjusting a bandana will now take if off of your head/face and put it in an available hand. If both hands are available, it goes in the selected hand." - - bugfix: "Adjusting a coloured bandana will no longer revert it to the original coloured icons anymore." - - bugfix: "Adjusting a bandana from mask-style to hat-style means the bandana won't obscure your identity anymore." diff --git a/html/changelogs/AutoChangeLog-pr-3556.yml b/html/changelogs/AutoChangeLog-pr-3556.yml deleted file mode 100644 index b7aedebe4fe..00000000000 --- a/html/changelogs/AutoChangeLog-pr-3556.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: Crazylemon64 -delete-after: True -changes: - - tweak: "Relaxes the check on what atoms you can follow to any movable atom" diff --git a/html/changelogs/AutoChangeLog-pr-3557.yml b/html/changelogs/AutoChangeLog-pr-3557.yml deleted file mode 100644 index fdc062cb3eb..00000000000 --- a/html/changelogs/AutoChangeLog-pr-3557.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: Fox McCloud -delete-after: True -changes: - - tweak: "Updates some spell icons with better/higher quality icons" diff --git a/html/changelogs/AutoChangeLog-pr-3559.yml b/html/changelogs/AutoChangeLog-pr-3559.yml deleted file mode 100644 index ac56a2bfa3a..00000000000 --- a/html/changelogs/AutoChangeLog-pr-3559.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: Crazylemon64 -delete-after: True -changes: - - tweak: "Mages are now more ragin" - - tweak: "Admins can now adjust the total number of wizards at runtime by tweaking either max_mages, or players_per mage" diff --git a/html/changelogs/AutoChangeLog-pr-3560.yml b/html/changelogs/AutoChangeLog-pr-3560.yml deleted file mode 100644 index cef1c0c229f..00000000000 --- a/html/changelogs/AutoChangeLog-pr-3560.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: DaveTheHeadcrab -delete-after: True -changes: - - rscadd: "Adds new worn icons for duffelbags to better reflect their size, compliments of WJohn at /tg/" diff --git a/html/changelogs/AutoChangeLog-pr-3568.yml b/html/changelogs/AutoChangeLog-pr-3568.yml deleted file mode 100644 index 2ca65994c33..00000000000 --- a/html/changelogs/AutoChangeLog-pr-3568.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: KasparoVy -delete-after: True -changes: - - rscadd: "Greys now use re-positioned smokeables. They no longer smoke out the eyes." diff --git a/html/changelogs/AutoChangeLog-pr-3569.yml b/html/changelogs/AutoChangeLog-pr-3569.yml deleted file mode 100644 index 29aa056157c..00000000000 --- a/html/changelogs/AutoChangeLog-pr-3569.yml +++ /dev/null @@ -1,12 +0,0 @@ -author: Fox McCloud -delete-after: True -changes: - - tweak: "Updates unarmed attacks to allow for more customization" - - tweak: "Updates martial arts so they factor in specie's attack messages and sounds" - - tweak: "Re-balances Sleeping Carp fighting style" - - tweak: "Re-balances Bo Staff" - - tweak: "Rebalances Golem: they should now be spaceproof, fire+cold proof, rad proof, virus immune, clonable, parapen+syringe gun immune, deal increased melee damage. Their armor has been reduced to 55 melee across the board, their slip immunity removed, pain immunity removed, and they're slightly slower" - - bugfix: "Fixes Ei Nath generating two brains" - - bugfix: "Ensures the Necromatic Stone generates actual skeletons" - - bugfix: "Can now strip PDA/IDs from Golems" - - bugfix: "Fixes sleeping carp grab not being an instant aggressive grab" diff --git a/html/changelogs/AutoChangeLog-pr-3575.yml b/html/changelogs/AutoChangeLog-pr-3575.yml deleted file mode 100644 index c32ed0c1f09..00000000000 --- a/html/changelogs/AutoChangeLog-pr-3575.yml +++ /dev/null @@ -1,8 +0,0 @@ -author: TheDZD -delete-after: True -changes: - - bugfix: "Fixes spacepods being able to shoot through walls." - - tweak: "Lowers spacepod weapons fire delay." - - tweak: "Increases spacepod weapons energy costs." - - tweak: "Makes spacepods move at speeds not rivaling those of photon beams. They are now a hair bit faster than a person with a jetpack." - - tweak: "Reduces battery costs for spacepod movement." diff --git a/html/changelogs/AutoChangeLog-pr-3576.yml b/html/changelogs/AutoChangeLog-pr-3576.yml deleted file mode 100644 index f6d9443efcc..00000000000 --- a/html/changelogs/AutoChangeLog-pr-3576.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: FalseIncarnate -delete-after: True -changes: - - rscadd: "Adds burritos, made from cutlets, beans, rice, capsacin oil (hotsauce), cheese, and flat dough (because we lack proper tortillas) in the microwave." - - rscadd: "Adds chimichangas. You know you want a deep-fried burrito." diff --git a/html/changelogs/AutoChangeLog-pr-3578.yml b/html/changelogs/AutoChangeLog-pr-3578.yml new file mode 100644 index 00000000000..caa61d1c3e1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3578.yml @@ -0,0 +1,4 @@ +author: Tastyfish +delete-after: True +changes: + - tweak: "The PDA system has been completely redone behind the scenes! It should be functionally similar, although there is now a Home and Back button at the bottom as appropriate." diff --git a/html/changelogs/AutoChangeLog-pr-3584.yml b/html/changelogs/AutoChangeLog-pr-3584.yml deleted file mode 100644 index 98ed8cd34bb..00000000000 --- a/html/changelogs/AutoChangeLog-pr-3584.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: Fox McCloud -delete-after: True -changes: - - bugfix: "Fixes an exploit with declaring war on the station" diff --git a/html/changelogs/AutoChangeLog-pr-3585.yml b/html/changelogs/AutoChangeLog-pr-3585.yml new file mode 100644 index 00000000000..91d6a32535b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3585.yml @@ -0,0 +1,4 @@ +author: Tastyfish +delete-after: True +changes: + - rscadd: "All of the heads now have multicolored pens." diff --git a/html/changelogs/AutoChangeLog-pr-3599.yml b/html/changelogs/AutoChangeLog-pr-3599.yml new file mode 100644 index 00000000000..d4297aa6495 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3599.yml @@ -0,0 +1,5 @@ +author: KasparoVy +delete-after: True +changes: + - bugfix: "Adjusting masks while they are not on the face will no longer turn off internals." + - bugfix: "Adjusting masks while they are not on the face will now cause the mask to hide/reveal the wearer's identity the next time it's worn as intended." diff --git a/html/changelogs/AutoChangeLog-pr-3600.yml b/html/changelogs/AutoChangeLog-pr-3600.yml new file mode 100644 index 00000000000..34aa345cbc3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3600.yml @@ -0,0 +1,4 @@ +author: Fox McCloud +delete-after: True +changes: + - tweak: "Laser eyes mutation no longer drains nutrition" diff --git a/html/changelogs/AutoChangeLog-pr-3601.yml b/html/changelogs/AutoChangeLog-pr-3601.yml new file mode 100644 index 00000000000..e0099cb3060 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3601.yml @@ -0,0 +1,7 @@ +author: FalseIncarnate +delete-after: True +changes: + - rscadd: "Adds prize tickets as a replacement for physical arcade prizes." + - rscadd: "Adds a buildable prize counter to exchange tickets for prizes." + - rscadd: "Adds a bike. Despite what Prof. Oak might claim, you can ride it indoors." + - rscadd: "Adds colorful wallets, for that old school arcade pride." diff --git a/html/changelogs/AutoChangeLog-pr-3603.yml b/html/changelogs/AutoChangeLog-pr-3603.yml new file mode 100644 index 00000000000..a77a20fb692 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3603.yml @@ -0,0 +1,4 @@ +author: FalseIncarnate +delete-after: True +changes: + - bugfix: "Fixes accidental removal of plump helmet biscuit recipe." diff --git a/html/changelogs/AutoChangeLog-pr-3608.yml b/html/changelogs/AutoChangeLog-pr-3608.yml new file mode 100644 index 00000000000..fd3ace9ea8e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3608.yml @@ -0,0 +1,4 @@ +author: Fox McCloud +delete-after: True +changes: + - tweak: "splits the EMP kit into two things: the standard EMP kit (2 grenades and an implant), and the EMP flashlight by itself" diff --git a/html/changelogs/AutoChangeLog-pr-3610.yml b/html/changelogs/AutoChangeLog-pr-3610.yml new file mode 100644 index 00000000000..8d52a9e03fa --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3610.yml @@ -0,0 +1,4 @@ +author: Spacemanspark +delete-after: True +changes: + - rscadd: "Adds *yes and *no emotes to Synthetics. Glory to Synthetica." diff --git a/html/changelogs/AutoChangeLog-pr-3612.yml b/html/changelogs/AutoChangeLog-pr-3612.yml new file mode 100644 index 00000000000..2583bcd98f5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3612.yml @@ -0,0 +1,4 @@ +author: Crazylemon64 +delete-after: True +changes: + - rscadd: "Attacking someone with an accessory will now let you put things on them without having to strip them." diff --git a/html/changelogs/AutoChangeLog-pr-3614.yml b/html/changelogs/AutoChangeLog-pr-3614.yml new file mode 100644 index 00000000000..528eadcfc9e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3614.yml @@ -0,0 +1,9 @@ +author: Crazylemon64 +delete-after: True +changes: + - bugfix: "Borers will now properly detach upon death of a mob they are controlling" + - tweak: "Borers can now see their chemical count while in control of a mob" + - rscadd: "Borers can now silently communicate with their host - this is not available to the host until the borer has either begun to communicate, or has taken control at least once - this is to avoid spoiling that the borer exists" + - tweak: "Borers won't be able to talk out loud inside of a host, by default - they can remove this safeguard with a verb under their borer tab. Borer hivespeak is unaffected." + - tweak: "Borers infesting and hiding are now silent." + - tweak: "Made borer's chem lists more nicely formatted" diff --git a/html/changelogs/AutoChangeLog-pr-3622.yml b/html/changelogs/AutoChangeLog-pr-3622.yml new file mode 100644 index 00000000000..6a10ff80c22 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3622.yml @@ -0,0 +1,5 @@ +author: Tastyfish +delete-after: True +changes: + - rscadd: "EngiVend now has 10 camera assemblies." + - tweak: "Borgs can now use vending machines." diff --git a/html/changelogs/AutoChangeLog-pr-3633.yml b/html/changelogs/AutoChangeLog-pr-3633.yml new file mode 100644 index 00000000000..b7a239dd37a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3633.yml @@ -0,0 +1,5 @@ +author: FalseIncarnate +delete-after: True +changes: + - rscadd: "Temporarily adds a prize counter to the bar (Cyberiad) or dorms (MetaStation), and adds a max upgrade one to the Ninja Holding Area (Cyberiad z2)" + - bugfix: "Fixes Metastation. Seriously fixed a lot, just read the PR description for the full list." diff --git a/icons/obj/arcade.dmi b/icons/obj/arcade.dmi index 50f8e800273..9861aea35c9 100644 Binary files a/icons/obj/arcade.dmi and b/icons/obj/arcade.dmi differ diff --git a/icons/obj/wallets.dmi b/icons/obj/wallets.dmi new file mode 100644 index 00000000000..0a96bc16f5c Binary files /dev/null and b/icons/obj/wallets.dmi differ diff --git a/icons/turf/floors.dmi b/icons/turf/floors.dmi index 18dd60eb768..8e7e4d25454 100644 Binary files a/icons/turf/floors.dmi and b/icons/turf/floors.dmi differ diff --git a/icons/vehicles/motorcycle.dmi b/icons/vehicles/motorcycle.dmi index 8b5a004fa5d..2f3c2d5517f 100644 Binary files a/icons/vehicles/motorcycle.dmi and b/icons/vehicles/motorcycle.dmi differ diff --git a/interface/stylesheet.dm b/interface/stylesheet.dm index a8ba16b7b69..b045e1adbdc 100644 --- a/interface/stylesheet.dm +++ b/interface/stylesheet.dm @@ -20,7 +20,7 @@ em {font-style: normal; font-weight: bold;} .adminobserverooc {color: #0099cc; font-weight: bold;} .adminooc {color: #b82e00; font-weight: bold;} .mentorhelp {color: #0077bb; font-weight: bold;} -.adminhelp {color: #aa0000; font-weight: bolt;} +.adminhelp {color: #aa0000; font-weight: bold;} .adminobserver {color: #996600; font-weight: bold;} .admin {color: #386aff; font-weight: bold;} diff --git a/nano/assets/nano.js b/nano/assets/nano.js index 9ae1ecc460a..3c4944c74b7 100644 --- a/nano/assets/nano.js +++ b/nano/assets/nano.js @@ -1 +1 @@ -function NanoStateDefaultClass(){this.key="default",this.key=this.key.toLowerCase(),NanoStateManager.addState(this)}function NanoStateClass(){}var NanoUtility=function(){var e={};return{init:function(){var t=$("body");e=t.data("urlParameters")},generateHref:function(t){var n="?";for(var a in e)e.hasOwnProperty(a)&&("?"!==n&&(n+=";"),n+=a+"="+e[a]);for(var a in t)t.hasOwnProperty(a)&&("?"!==n&&(n+=";"),n+=a+"="+t[a]);return n},winset:function(e,t,n){var a,r;return null==n&&(n=NanoStateManager.getData().config.window.ref),a={},a[n+"."+e]=t,r=a,location.href=NanoUtility.href("winset",r)},extend:function(e,t){return Object.keys(t).forEach(function(n){var a;return a=t[n],a&&"[object Object]"===Object.prototype.toString.call(a)?(e[n]=e[n]||{},NanoUtility.extend(e[n],a)):e[n]=a}),e},href:function(e,t){return null==e&&(e=""),null==t&&(t={}),e=new Url("byond://"+e),NanoUtility.extend(e.query,t),e},close:function(){var t;return t={command:"nanoclose "+e.src},this.winset("is-visible","false"),location.href=NanoUtility.href("winset",t)}}}();"undefined"==typeof jQuery&&reportError("ERROR: Javascript library failed to load!"),"undefined"==typeof doT&&reportError("ERROR: Template engine failed to load!");var reportError=function(e){window.location="byond://?nano_err="+encodeURIComponent(e),alert(e)};$(document).ready(function(){NanoUtility.init(),NanoStateManager.init(),NanoTemplate.init(),NanoWindow.init()}),Array.prototype.indexOf||(Array.prototype.indexOf=function(e){var t=this.length,n=Number(arguments[1])||0;for(n=0>n?Math.ceil(n):Math.floor(n),0>n&&(n+=t);t>n;n++)if(n in this&&this[n]===e)return n;return-1}),String.prototype.format||(String.prototype.format=function(e){var t=this;return t.replace(String.prototype.format.regex,function(t){var n,a=parseInt(t.substring(1,t.length-1));return n=a>=0?e[a]:-1===a?"{":-2===a?"}":""})},String.prototype.format.regex=new RegExp("{-?[0-9]+}","g")),Object.size=function(e){var t,n=0;for(var t in e)e.hasOwnProperty(t)&&n++;return n},window.console||(window.console={log:function(e){return!1}}),String.prototype.toTitleCase=function(){var e=/^(a|an|and|as|at|but|by|en|for|if|in|of|on|or|the|to|vs?\.?|via)$/i;return this.replace(/([^\W_]+[^\s-]*) */g,function(t,n,a,r){return a>0&&a+n.length!==r.length&&n.search(e)>-1&&":"!==r.charAt(a-2)&&r.charAt(a-1).search(/[^\s-]/)<0?t.toLowerCase():n.substr(1).search(/[A-Z]|\../)>-1?t:t.charAt(0).toUpperCase()+t.substr(1)})},$.ajaxSetup({cache:!1}),Function.prototype.inheritsFrom=function(e){return this.prototype=new e,this.prototype.constructor=this,this.prototype.parent=e.prototype,this},String.prototype.trim||(String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g,"")}),String.prototype.ckey||(String.prototype.ckey=function(){return this.replace(/\W/g,"").toLowerCase()}),NanoStateManager=function(){var e=!1,t=null,n={},a={},r={},o=null,i=function(){t=$("body").data("initialData"),null!=t&&t.hasOwnProperty("config")&&t.hasOwnProperty("data")||reportError("Error: Initial data did not load correctly.");var n="default";t.config.hasOwnProperty("stateKey")&&t.config.stateKey&&(n=t.config.stateKey.toLowerCase()),NanoStateManager.setCurrentState(n),$(document).on("templatesLoaded",function(){l(t),e=!0})},s=function(n){var a;try{a=jQuery.parseJSON(n)}catch(r){return void reportError("recieveUpdateData failed.
    Error name: "+r.name+"
    Error Message: "+r.message)}a.hasOwnProperty("data")||(t&&t.hasOwnProperty("data")?a.data=t.data:a.data={}),e?l(a):t=a},l=function(e){if(null!=o){if(e=o.onBeforeUpdate(e),e===!1)return void reportError("data is false, return");t=e,o.onUpdate(t),o.onAfterUpdate(t)}},c=function(e,t){for(var n in e)e.hasOwnProperty(n)&&jQuery.isFunction(e[n])&&(t=e[n].call(this,t));return t};return{init:function(){i()},receiveUpdateData:function(e){s(e)},addBeforeUpdateCallback:function(e,t){n[e]=t},addBeforeUpdateCallbacks:function(e){for(var t in e)e.hasOwnProperty(t)&&NanoStateManager.addBeforeUpdateCallback(t,e[t])},removeBeforeUpdateCallback:function(e){n.hasOwnProperty(e)&&delete n[e]},executeBeforeUpdateCallbacks:function(e){return c(n,e)},addAfterUpdateCallback:function(e,t){a[e]=t},addAfterUpdateCallbacks:function(e){for(var t in e)e.hasOwnProperty(t)&&NanoStateManager.addAfterUpdateCallback(t,e[t])},removeAfterUpdateCallback:function(e){a.hasOwnProperty(e)&&delete a[e]},executeAfterUpdateCallbacks:function(e){return c(a,e)},addState:function(e){return e instanceof NanoStateClass?e.key?void(r[e.key]=e):void reportError("ERROR: Attempted to add a state with an invalid stateKey"):void reportError("ERROR: Attempted to add a state which is not instanceof NanoStateClass")},setCurrentState:function(e){if("undefined"==typeof e||!e)return reportError("ERROR: No state key was passed!"),!1;if(!r.hasOwnProperty(e))return reportError("ERROR: Attempted to set a current state which does not exist: "+e),!1;var t=o;return o=r[e],null!=t&&t.onRemove(o),o.onAdd(t),!0},getCurrentState:function(){return o},getData:function(){return t}}}(),NanoBaseCallbacks=function(){var e=!0,t={},n={status:function(t){var n;return 2==t.config.status?(n="good",$(".linkActive").removeClass("inactive")):1==t.config.status?(n="average",$(".linkActive").addClass("inactive")):(n="bad",$(".linkActive").addClass("inactive")),$(".statusicon").removeClass("good bad average").addClass(n),$(".linkActive").stopTime("linkPending"),$(".linkActive").removeClass("linkPending"),$(".linkActive").off("click").on("click",function(n){n.preventDefault();var a=$(this).data("href");null!=a&&e&&(e=!1,$("body").oneTime(300,"enableClick",function(){e=!0}),2==t.config.status&&$(this).oneTime(300,"linkPending",function(){$(this).addClass("linkPending")}),window.location.href=a)}),t},nanomap:function(e){return $(".mapIcon").off("mouseenter mouseleave").on("mouseenter",function(e){$("#uiMapTooltip").html($(this).children(".tooltip").html()).show().stopTime().oneTime(5e3,"hideTooltip",function(){$(this).fadeOut(500)})}),$(".zoomLink").off("click").on("click",function(e){e.preventDefault();var t=$(this).data("zoomLevel"),n=$("#uiMap"),a=n.width()*t,r=n.height()*t;n.css({zoom:t,left:"50%",top:"50%",marginLeft:"-"+Math.floor(a/2)+"px",marginTop:"-"+Math.floor(r/2)+"px"})}),$("#uiMapImage").attr("src","nanomap_z"+e.config.mapZLevel+".png"),e}};return{addCallbacks:function(){NanoStateManager.addBeforeUpdateCallbacks(t),NanoStateManager.addAfterUpdateCallbacks(n)},removeCallbacks:function(){for(var e in t)t.hasOwnProperty(e)&&NanoStateManager.removeBeforeUpdateCallback(e);for(var e in n)n.hasOwnProperty(e)&&NanoStateManager.removeAfterUpdateCallback(e)}}}(),NanoBaseHelpers=function(){var e={syndicateMode:function(){return $("body").css("background-color","#8f1414"),$("body").css("background-image","url('uiBackground-Syndicate.png')"),$("body").css("background-position","50% 0"),$("body").css("background-repeat","repeat-x"),$("#uiTitleFluff").css("background-image","url('uiTitleFluff-Syndicate.png')"),$("#uiTitleFluff").css("background-position","50% 50%"),$("#uiTitleFluff").css("background-repeat","no-repeat"),""},combine:function(e,t){return e&&t?e.concat(t):e||t},dump:function(e){return JSON.stringify(e)},link:function(e,t,n,a,r,o){var i="",s="noIcon";"undefined"!=typeof t&&t&&(i='
    ',s="hasIcon"),"undefined"!=typeof r&&r||(r="link");var l="";return"undefined"!=typeof o&&o&&(l='id="'+o+'"'),"undefined"!=typeof a&&a?'":'
    "+i+e+"
    "},xor:function(e,t){return e^t},precisionRound:function(e,t){if(0==t)return Math.round(number);var n=Math.pow(10,t);return Math.round(e*n)/n},round:function(e){return Math.round(e)},fixed:function(e){return Math.round(10*e)/10},floor:function(e){return Math.floor(e)},ceil:function(e){return Math.ceil(e)},string:function(){if(0==arguments.length)return"";if(1==arguments.length)return arguments[0];if(arguments.length>1){stringArgs=[];for(var e=1;et?t>e?e=t:e>n&&(e=n):e>t?e=t:n>e&&(e=n),"undefined"!=typeof a&&a||(a=""),"undefined"!=typeof r&&r||(r="");var o=Math.round((e-t)/(n-t)*100);return'
    '+r+"
    "},dangerToClass:function(e){return 0==e?"good":1==e?"average":"bad"},dangerToSpan:function(e){return 0==e?'"Good"':1==e?'"Minor Alert"':'"Major Alert"'},generateHref:function(e){var t=$("body");_urlParameters=t.data("urlParameters");var n="?";for(var a in _urlParameters)_urlParameters.hasOwnProperty(a)&&("?"!==n&&(n+=";"),n+=a+"="+_urlParameters[a]);for(var a in e)e.hasOwnProperty(a)&&("?"!==n&&(n+=";"),n+=a+"="+e[a]);return n},displayDNABlocks:function(e,t,n,a,r){if(!e)return'
    Please place a valid subject into the DNA modifier.
    ';var o=e.split(""),i='
    ',s=1,l=1;for(var c in o)if(o.hasOwnProperty(c)&&"object"!=typeof o[c]){var u;u="UI"==r.toUpperCase()?{selectUIBlock:s,selectUISubblock:l}:{selectSEBlock:s,selectSESubblock:l};var d="linkActive";s==t&&l==n&&(d="selected"),i+='",c++,c%a==0&&c
    "):l++}return i+="
    "},cMirror:function(e){CodeMirror.fromTextArea(document.getElementById(e),{lineNumbers:!0,indentUnit:4,indentWithTabs:!0,theme:"lesser-dark"})}};return{addHelpers:function(){NanoTemplate.addHelpers(e)},removeHelpers:function(){for(var t in e)e.hasOwnProperty(t)&&NanoTemplate.removeHelper(t)}}}(),NanoStateDefaultClass.inheritsFrom(NanoStateClass);var NanoStateDefault=new NanoStateDefaultClass;NanoStateClass.prototype.key=null,NanoStateClass.prototype.layoutRendered=!1,NanoStateClass.prototype.contentRendered=!1,NanoStateClass.prototype.mapInitialised=!1,NanoStateClass.prototype.isCurrent=function(){return NanoStateManager.getCurrentState()==this},NanoStateClass.prototype.onAdd=function(e){NanoBaseCallbacks.addCallbacks(),NanoBaseHelpers.addHelpers()},NanoStateClass.prototype.onRemove=function(e){NanoBaseCallbacks.removeCallbacks(),NanoBaseHelpers.removeHelpers()},NanoStateClass.prototype.onBeforeUpdate=function(e){return e=NanoStateManager.executeBeforeUpdateCallbacks(e)},NanoStateClass.prototype.onUpdate=function(e){try{(!this.layoutRendered||e.config.hasOwnProperty("autoUpdateLayout")&&e.config.autoUpdateLayout)&&($("#uiLayout").html(NanoTemplate.parse("layout",e)),this.layoutRendered=!0),(!this.contentRendered||e.config.hasOwnProperty("autoUpdateContent")&&e.config.autoUpdateContent)&&($("#uiContent").html(NanoTemplate.parse("main",e)),this.contentRendered=!0),NanoTemplate.templateExists("mapContent")&&(this.mapInitialised||($("#uiMap").draggable(),$("#uiMapTooltip").off("click").on("click",function(e){e.preventDefault(),$(this).fadeOut(400)}),this.mapInitialised=!0),$("#uiMapContent").html(NanoTemplate.parse("mapContent",e)),e.config.hasOwnProperty("showMap")&&e.config.showMap?($("#uiContent").addClass("hidden"),$("#uiMapWrapper").removeClass("hidden")):($("#uiMapWrapper").addClass("hidden"),$("#uiContent").removeClass("hidden"))),NanoTemplate.templateExists("mapHeader")&&$("#uiMapHeader").html(NanoTemplate.parse("mapHeader",e)),NanoTemplate.templateExists("mapFooter")&&$("#uiMapFooter").html(NanoTemplate.parse("mapFooter",e))}catch(t){return void reportError("ERROR: An error occurred while rendering the UI: "+t.message)}},NanoStateClass.prototype.onAfterUpdate=function(e){NanoStateManager.executeAfterUpdateCallbacks(e)},NanoStateClass.prototype.alertText=function(e){alert(e)};var NanoTemplate=function(){var e={},t={},n={},a={},r=function(){e=$("body").data("templateData"),null==e&&reportError("Error: Template data did not load correctly."),o()},o=function(){var t=Object.size(e);if(!t)return void $(document).trigger("templatesLoaded");for(var n in e)if(e.hasOwnProperty(n))return void $.when($.ajax({url:e[n],cache:!1,dataType:"text"})).done(function(t){t+='
    ';try{NanoTemplate.addTemplate(n,t)}catch(a){return void reportError("ERROR: An error occurred while loading the UI: "+a.message)}delete e[n],o()}).fail(function(){reportError("ERROR: Loading template "+n+"("+e[n]+") failed!")})},i=function(){for(var e in t)try{n[e]=doT.template(t[e],null,t)}catch(a){reportError(a.message)}};return{init:function(){r()},addTemplate:function(e,n){t[e]=n},templateExists:function(e){return t.hasOwnProperty(e)},parse:function(e,r){if(!n.hasOwnProperty(e)||!n[e]){if(!t.hasOwnProperty(e))return reportError('ERROR: Template "'+e+'" does not exist in _compiledTemplates!'),"

    Template error (does not exist)

    ";i()}return"function"!=typeof n[e]?(reportError(n[e]),reportError('ERROR: Template "'+e+'" failed to compile!'),"

    Template error (failed to compile)

    "):n[e].call(this,r.data,r.config,a)},addHelper:function(e,t){return jQuery.isFunction(t)?void(a[e]=t):void reportError("NanoTemplate.addHelper failed to add "+e+" as it is not a function.")},addHelpers:function(e){for(var t in e)e.hasOwnProperty(t)&&NanoTemplate.addHelper(t,e[t])},removeHelper:function(e){helpers.hasOwnProperty(e)&&delete a[e]}}}(),NanoWindow=function(){var e,t,n,a,r,o,i=function(e,t){NanoUtility.winset("pos",e+","+t)},s=function(e,t){NanoUtility.winset("size",e+","+t)},l=function(){NanoStateManager.getData().config.user.fancy&&(c(),u(),d(),f())},c=function(){NanoUtility.winset("titlebar",0),NanoUtility.winset("can-resize",0),$(".fancy").show(),$("#uiTitleFluff").css("right","65px")},u=function(){var e=function(){return NanoUtility.close()},t=function(){return NanoUtility.winset("is-minimized","true")};$(".close").on("click",function(t){e()}),$(".minimize").on("click",function(e){t()})},d=function(){$("#uiTitleWrapper").on("mousemove",function(e){p()}),$("#uiTitleWrapper").on("mousedown",function(t){e=!0}),$("#uiTitleWrapper").on("mouseup",function(a){e=!1,t=null,n=null})},p=function(a){var r,o;null==a&&(a=window.event),e&&(null==t&&(t=a.screenX),null==n&&(n=a.screenY),r=a.screenX-t+window.screenLeft,o=a.screenY-n+window.screenTop,i(r,o),t=a.screenX,n=a.screenY)},f=function(){$("#resize").on("mousemove",function(e){m()}),$("#resize").on("mousedown",function(e){a=!0}),$("#resize").on("mouseup",function(e){a=!1})},m=function(){var e,t;null==event&&(event=window.event),a&&(null==r&&(r=event.screenX),null==o&&(o=event.screenY),e=Math.max(150,event.screenX-r+window.innerWidth),t=Math.max(150,event.screenY-o+window.innerHeight),s(e,t),r=event.screenX,o=event.screenY)};return{init:function(){$(document).on("templatesLoaded",function(){l()})}}}(); \ No newline at end of file +function NanoStateDefaultClass(){this.key="default",this.key=this.key.toLowerCase(),NanoStateManager.addState(this)}function NanoStatePDAClass(){this.key="pda",this.key=this.key.toLowerCase(),this.current_template="",NanoStateManager.addState(this)}function NanoStateClass(){}var NanoUtility=function(){var e={};return{init:function(){var t=$("body");e=t.data("urlParameters")},generateHref:function(t){var n="?";for(var a in e)e.hasOwnProperty(a)&&("?"!==n&&(n+=";"),n+=a+"="+e[a]);for(var a in t)t.hasOwnProperty(a)&&("?"!==n&&(n+=";"),n+=a+"="+t[a]);return n},winset:function(e,t,n){var a,r;return null==n&&(n=NanoStateManager.getData().config.window.ref),a={},a[n+"."+e]=t,r=a,location.href=NanoUtility.href("winset",r)},extend:function(e,t){return Object.keys(t).forEach(function(n){var a;return a=t[n],a&&"[object Object]"===Object.prototype.toString.call(a)?(e[n]=e[n]||{},NanoUtility.extend(e[n],a)):e[n]=a}),e},href:function(e,t){return null==e&&(e=""),null==t&&(t={}),e=new Url("byond://"+e),NanoUtility.extend(e.query,t),e},close:function(){var t;return t={command:"nanoclose "+e.src},this.winset("is-visible","false"),location.href=NanoUtility.href("winset",t)}}}();"undefined"==typeof jQuery&&reportError("ERROR: Javascript library failed to load!"),"undefined"==typeof doT&&reportError("ERROR: Template engine failed to load!");var reportError=function(e){window.location="byond://?nano_err="+encodeURIComponent(e),alert(e)};$(document).ready(function(){NanoUtility.init(),NanoStateManager.init(),NanoTemplate.init(),NanoWindow.init()}),Array.prototype.indexOf||(Array.prototype.indexOf=function(e){var t=this.length,n=Number(arguments[1])||0;for(n=0>n?Math.ceil(n):Math.floor(n),0>n&&(n+=t);t>n;n++)if(n in this&&this[n]===e)return n;return-1}),String.prototype.format||(String.prototype.format=function(e){var t=this;return t.replace(String.prototype.format.regex,function(t){var n,a=parseInt(t.substring(1,t.length-1));return n=a>=0?e[a]:-1===a?"{":-2===a?"}":""})},String.prototype.format.regex=new RegExp("{-?[0-9]+}","g")),Object.size=function(e){var t,n=0;for(var t in e)e.hasOwnProperty(t)&&n++;return n},window.console||(window.console={log:function(e){return!1}}),String.prototype.toTitleCase=function(){var e=/^(a|an|and|as|at|but|by|en|for|if|in|of|on|or|the|to|vs?\.?|via)$/i;return this.replace(/([^\W_]+[^\s-]*) */g,function(t,n,a,r){return a>0&&a+n.length!==r.length&&n.search(e)>-1&&":"!==r.charAt(a-2)&&r.charAt(a-1).search(/[^\s-]/)<0?t.toLowerCase():n.substr(1).search(/[A-Z]|\../)>-1?t:t.charAt(0).toUpperCase()+t.substr(1)})},$.ajaxSetup({cache:!1}),Function.prototype.inheritsFrom=function(e){return this.prototype=new e,this.prototype.constructor=this,this.prototype.parent=e.prototype,this},String.prototype.trim||(String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g,"")}),String.prototype.ckey||(String.prototype.ckey=function(){return this.replace(/\W/g,"").toLowerCase()}),NanoStateManager=function(){var e=!1,t=null,n={},a={},r={},o=null,i=function(){t=$("body").data("initialData"),null!=t&&t.hasOwnProperty("config")&&t.hasOwnProperty("data")||reportError("Error: Initial data did not load correctly.");var n="default";t.config.hasOwnProperty("stateKey")&&t.config.stateKey&&(n=t.config.stateKey.toLowerCase()),NanoStateManager.setCurrentState(n),$(document).on("templatesLoaded",function(){l(t),e=!0})},s=function(n){var a;try{a=jQuery.parseJSON(n)}catch(r){return void reportError("recieveUpdateData failed.
    Error name: "+r.name+"
    Error Message: "+r.message)}a.hasOwnProperty("data")||(t&&t.hasOwnProperty("data")?a.data=t.data:a.data={}),e?l(a):t=a},l=function(e){if(null!=o){if(e=o.onBeforeUpdate(e),e===!1)return void reportError("data is false, return");t=e,o.onUpdate(t),o.onAfterUpdate(t)}},c=function(e,t){for(var n in e)e.hasOwnProperty(n)&&jQuery.isFunction(e[n])&&(t=e[n].call(this,t));return t};return{init:function(){i()},receiveUpdateData:function(e){s(e)},addBeforeUpdateCallback:function(e,t){n[e]=t},addBeforeUpdateCallbacks:function(e){for(var t in e)e.hasOwnProperty(t)&&NanoStateManager.addBeforeUpdateCallback(t,e[t])},removeBeforeUpdateCallback:function(e){n.hasOwnProperty(e)&&delete n[e]},executeBeforeUpdateCallbacks:function(e){return c(n,e)},addAfterUpdateCallback:function(e,t){a[e]=t},addAfterUpdateCallbacks:function(e){for(var t in e)e.hasOwnProperty(t)&&NanoStateManager.addAfterUpdateCallback(t,e[t])},removeAfterUpdateCallback:function(e){a.hasOwnProperty(e)&&delete a[e]},executeAfterUpdateCallbacks:function(e){return c(a,e)},addState:function(e){return e instanceof NanoStateClass?e.key?void(r[e.key]=e):void reportError("ERROR: Attempted to add a state with an invalid stateKey"):void reportError("ERROR: Attempted to add a state which is not instanceof NanoStateClass")},setCurrentState:function(e){if("undefined"==typeof e||!e)return reportError("ERROR: No state key was passed!"),!1;if(!r.hasOwnProperty(e))return reportError("ERROR: Attempted to set a current state which does not exist: "+e),!1;var t=o;return o=r[e],null!=t&&t.onRemove(o),o.onAdd(t),!0},getCurrentState:function(){return o},getData:function(){return t}}}(),NanoBaseCallbacks=function(){var e=!0,t={},n={status:function(t){var n;return 2==t.config.status?(n="good",$(".linkActive").removeClass("inactive")):1==t.config.status?(n="average",$(".linkActive").addClass("inactive")):(n="bad",$(".linkActive").addClass("inactive")),$(".statusicon").removeClass("good bad average").addClass(n),$(".linkActive").stopTime("linkPending"),$(".linkActive").removeClass("linkPending"),$(".linkActive").off("click").on("click",function(n){n.preventDefault();var a=$(this).data("href");null!=a&&e&&(e=!1,$("body").oneTime(300,"enableClick",function(){e=!0}),2==t.config.status&&$(this).oneTime(300,"linkPending",function(){$(this).addClass("linkPending")}),window.location.href=a)}),t},nanomap:function(e){return $(".mapIcon").off("mouseenter mouseleave").on("mouseenter",function(e){$("#uiMapTooltip").html($(this).children(".tooltip").html()).show().stopTime().oneTime(5e3,"hideTooltip",function(){$(this).fadeOut(500)})}),$(".zoomLink").off("click").on("click",function(e){e.preventDefault();var t=$(this).data("zoomLevel"),n=$("#uiMap"),a=n.width()*t,r=n.height()*t;n.css({zoom:t,left:"50%",top:"50%",marginLeft:"-"+Math.floor(a/2)+"px",marginTop:"-"+Math.floor(r/2)+"px"})}),$("#uiMapImage").attr("src","nanomap_z"+e.config.mapZLevel+".png"),e}};return{addCallbacks:function(){NanoStateManager.addBeforeUpdateCallbacks(t),NanoStateManager.addAfterUpdateCallbacks(n)},removeCallbacks:function(){for(var e in t)t.hasOwnProperty(e)&&NanoStateManager.removeBeforeUpdateCallback(e);for(var e in n)n.hasOwnProperty(e)&&NanoStateManager.removeAfterUpdateCallback(e)}}}(),NanoBaseHelpers=function(){var e={syndicateMode:function(){return $("body").css("background-color","#8f1414"),$("body").css("background-image","url('uiBackground-Syndicate.png')"),$("body").css("background-position","50% 0"),$("body").css("background-repeat","repeat-x"),$("#uiTitleFluff").css("background-image","url('uiTitleFluff-Syndicate.png')"),$("#uiTitleFluff").css("background-position","50% 50%"),$("#uiTitleFluff").css("background-repeat","no-repeat"),""},combine:function(e,t){return e&&t?e.concat(t):e||t},dump:function(e){return JSON.stringify(e)},link:function(e,t,n,a,r,o){var i="",s="noIcon";"undefined"!=typeof t&&t&&(i='
    ',s="hasIcon"),"undefined"!=typeof r&&r||(r="link");var l="";return"undefined"!=typeof o&&o&&(l='id="'+o+'"'),"undefined"!=typeof a&&a?'":'
    "+i+e+"
    "},xor:function(e,t){return e^t},precisionRound:function(e,t){if(0==t)return Math.round(number);var n=Math.pow(10,t);return Math.round(e*n)/n},round:function(e){return Math.round(e)},fixed:function(e){return Math.round(10*e)/10},floor:function(e){return Math.floor(e)},ceil:function(e){return Math.ceil(e)},string:function(){if(0==arguments.length)return"";if(1==arguments.length)return arguments[0];if(arguments.length>1){stringArgs=[];for(var e=1;et?t>e?e=t:e>n&&(e=n):e>t?e=t:n>e&&(e=n),"undefined"!=typeof a&&a||(a=""),"undefined"!=typeof r&&r||(r="");var o=Math.round((e-t)/(n-t)*100);return'
    '+r+"
    "},dangerToClass:function(e){return 0==e?"good":1==e?"average":"bad"},dangerToSpan:function(e){return 0==e?'"Good"':1==e?'"Minor Alert"':'"Major Alert"'},generateHref:function(e){var t=$("body");_urlParameters=t.data("urlParameters");var n="?";for(var a in _urlParameters)_urlParameters.hasOwnProperty(a)&&("?"!==n&&(n+=";"),n+=a+"="+_urlParameters[a]);for(var a in e)e.hasOwnProperty(a)&&("?"!==n&&(n+=";"),n+=a+"="+e[a]);return n},displayDNABlocks:function(e,t,n,a,r){if(!e)return'
    Please place a valid subject into the DNA modifier.
    ';var o=e.split(""),i='
    ',s=1,l=1;for(var c in o)if(o.hasOwnProperty(c)&&"object"!=typeof o[c]){var u;u="UI"==r.toUpperCase()?{selectUIBlock:s,selectUISubblock:l}:{selectSEBlock:s,selectSESubblock:l};var d="linkActive";s==t&&l==n&&(d="selected"),i+='",c++,c%a==0&&c
    "):l++}return i+="
    "},cMirror:function(e){CodeMirror.fromTextArea(document.getElementById(e),{lineNumbers:!0,indentUnit:4,indentWithTabs:!0,theme:"lesser-dark"})}};return{addHelpers:function(){NanoTemplate.addHelpers(e)},removeHelpers:function(){for(var t in e)e.hasOwnProperty(t)&&NanoTemplate.removeHelper(t)}}}(),NanoStateDefaultClass.inheritsFrom(NanoStateClass);var NanoStateDefault=new NanoStateDefaultClass;NanoStatePDAClass.inheritsFrom(NanoStateClass);var NanoStatePDA=new NanoStatePDAClass;NanoStatePDAClass.prototype.onUpdate=function(e){NanoStateClass.prototype.onUpdate.call(this,e);var t=this;try{if(null!=e.data.app){var n=e.data.app.template;null!=n&&n!=t.current_template?$.when($.ajax({url:n+".tmpl",cache:!1,dataType:"text"})).done(function(a){a+='
    ';try{NanoTemplate.addTemplate("app",a),NanoTemplate.resetTemplate("app"),$("#uiApp").html(NanoTemplate.parse("app",e)),t.current_template=n,2==e.config.status&&($("#uiApp .linkActive").addClass("linkPending"),$("#uiApp .linkActive").oneTime(400,"linkPending",function(){$("#uiApp .linkActive").removeClass("linkPending inactive")}))}catch(r){return void reportError("ERROR: An error occurred while loading the PDA App UI: "+r.message)}}).fail(function(){reportError("ERROR: Loading template app("+n+") failed!")}):NanoTemplate.templateExists("app")&&$("#uiApp").html(NanoTemplate.parse("app",e))}}catch(a){return void reportError("ERROR: An error occurred while rendering the PDA App UI: "+a.message)}},NanoStateClass.prototype.key=null,NanoStateClass.prototype.layoutRendered=!1,NanoStateClass.prototype.contentRendered=!1,NanoStateClass.prototype.mapInitialised=!1,NanoStateClass.prototype.isCurrent=function(){return NanoStateManager.getCurrentState()==this},NanoStateClass.prototype.onAdd=function(e){NanoBaseCallbacks.addCallbacks(),NanoBaseHelpers.addHelpers()},NanoStateClass.prototype.onRemove=function(e){NanoBaseCallbacks.removeCallbacks(),NanoBaseHelpers.removeHelpers()},NanoStateClass.prototype.onBeforeUpdate=function(e){return e=NanoStateManager.executeBeforeUpdateCallbacks(e)},NanoStateClass.prototype.onUpdate=function(e){try{(!this.layoutRendered||e.config.hasOwnProperty("autoUpdateLayout")&&e.config.autoUpdateLayout)&&($("#uiLayout").html(NanoTemplate.parse("layout",e)),this.layoutRendered=!0),(!this.contentRendered||e.config.hasOwnProperty("autoUpdateContent")&&e.config.autoUpdateContent)&&($("#uiContent").html(NanoTemplate.parse("main",e)),this.contentRendered=!0),NanoTemplate.templateExists("mapContent")&&(this.mapInitialised||($("#uiMap").draggable(),$("#uiMapTooltip").off("click").on("click",function(e){e.preventDefault(),$(this).fadeOut(400)}),this.mapInitialised=!0),$("#uiMapContent").html(NanoTemplate.parse("mapContent",e)),e.config.hasOwnProperty("showMap")&&e.config.showMap?($("#uiContent").addClass("hidden"),$("#uiMapWrapper").removeClass("hidden")):($("#uiMapWrapper").addClass("hidden"),$("#uiContent").removeClass("hidden"))),NanoTemplate.templateExists("mapHeader")&&$("#uiMapHeader").html(NanoTemplate.parse("mapHeader",e)),NanoTemplate.templateExists("mapFooter")&&$("#uiMapFooter").html(NanoTemplate.parse("mapFooter",e))}catch(t){return void reportError("ERROR: An error occurred while rendering the UI: "+t.message)}},NanoStateClass.prototype.onAfterUpdate=function(e){NanoStateManager.executeAfterUpdateCallbacks(e)},NanoStateClass.prototype.alertText=function(e){alert(e)};var NanoTemplate=function(){var e={},t={},n={},a={},r=function(){e=$("body").data("templateData"),null==e&&reportError("Error: Template data did not load correctly."),o()},o=function(){var t=Object.size(e);if(!t)return void $(document).trigger("templatesLoaded");for(var n in e)if(e.hasOwnProperty(n))return void $.when($.ajax({url:e[n],cache:!1,dataType:"text"})).done(function(t){t+='
    ';try{NanoTemplate.addTemplate(n,t)}catch(a){return void reportError("ERROR: An error occurred while loading the UI: "+a.message)}delete e[n],o()}).fail(function(){reportError("ERROR: Loading template "+n+"("+e[n]+") failed!")})},i=function(){for(var e in t)try{n[e]=doT.template(t[e],null,t)}catch(a){reportError(a.message)}};return{init:function(){r()},addTemplate:function(e,n){t[e]=n},templateExists:function(e){return t.hasOwnProperty(e)},resetTemplate:function(e){n[e]=null},parse:function(e,r){if(!n.hasOwnProperty(e)||!n[e]){if(!t.hasOwnProperty(e))return reportError('ERROR: Template "'+e+'" does not exist in _compiledTemplates!'),"

    Template error (does not exist)

    ";i()}return"function"!=typeof n[e]?(reportError(n[e]),reportError('ERROR: Template "'+e+'" failed to compile!'),"

    Template error (failed to compile)

    "):n[e].call(this,r.data,r.config,a)},addHelper:function(e,t){return jQuery.isFunction(t)?void(a[e]=t):void reportError("NanoTemplate.addHelper failed to add "+e+" as it is not a function.")},addHelpers:function(e){for(var t in e)e.hasOwnProperty(t)&&NanoTemplate.addHelper(t,e[t])},removeHelper:function(e){helpers.hasOwnProperty(e)&&delete a[e]}}}(),NanoWindow=function(){var e,t,n,a,r,o,i=function(e,t){NanoUtility.winset("pos",e+","+t)},s=function(e,t){NanoUtility.winset("size",e+","+t)},l=function(){NanoStateManager.getData().config.user.fancy&&(c(),u(),d(),f())},c=function(){NanoUtility.winset("titlebar",0),NanoUtility.winset("can-resize",0),$(".fancy").show(),$("#uiTitleFluff").css("right","65px")},u=function(){var e=function(){return NanoUtility.close()},t=function(){return NanoUtility.winset("is-minimized","true")};$(".close").on("click",function(t){e()}),$(".minimize").on("click",function(e){t()})},d=function(){$("#uiTitleWrapper").on("mousemove",function(e){p()}),$("#uiTitleWrapper").on("mousedown",function(t){e=!0}),$("#uiTitleWrapper").on("mouseup",function(a){e=!1,t=null,n=null})},p=function(a){var r,o;null==a&&(a=window.event),e&&(null==t&&(t=a.screenX),null==n&&(n=a.screenY),r=a.screenX-t+window.screenLeft,o=a.screenY-n+window.screenTop,i(r,o),t=a.screenX,n=a.screenY)},f=function(){$("#resize").on("mousemove",function(e){m()}),$("#resize").on("mousedown",function(e){a=!0}),$("#resize").on("mouseup",function(e){a=!1})},m=function(){var e,t;null==event&&(event=window.event),a&&(null==r&&(r=event.screenX),null==o&&(o=event.screenY),e=Math.max(150,event.screenX-r+window.innerWidth),t=Math.max(150,event.screenY-o+window.innerHeight),s(e,t),r=event.screenX,o=event.screenY)};return{init:function(){$(document).on("templatesLoaded",function(){l()})}}}(); \ No newline at end of file diff --git a/nano/assets/nanoui.css b/nano/assets/nanoui.css index e99b2f94fd5..b4006f704b1 100644 --- a/nano/assets/nanoui.css +++ b/nano/assets/nanoui.css @@ -1,2 +1,2 @@ @font-face{font-family:FontAwesome;src:url(fontawesome-webfont.eot?v=4.5.0);src:url(fontawesome-webfont.eot?#iefix&v=4.5.0) format('embedded-opentype'),url(fontawesome-webfont.woff2?v=4.5.0) format('woff2'),url(fontawesome-webfont.woff?v=4.5.0) format('woff'),url(fontawesome-webfont.ttf?v=4.5.0) format('truetype'),url(fontawesome-webfont.svg?v=4.5.0#fontawesomeregular) format('svg');font-weight:400;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:a 2s infinite linear;animation:a 2s infinite linear}.fa-pulse{-webkit-animation:a 1s infinite steps(8);animation:a 1s infinite steps(8)}@-webkit-keyframes a{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes a{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0,mirror=1);-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2,mirror=1);-webkit-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-close:before,.fa-remove:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-cog:before,.fa-gear:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-repeat:before,.fa-rotate-right:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-exclamation-triangle:before,.fa-warning:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-cogs:before,.fa-gears:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-floppy-o:before,.fa-save:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-sort:before,.fa-unsorted:before{content:"\f0dc"}.fa-sort-desc:before,.fa-sort-down:before{content:"\f0dd"}.fa-sort-asc:before,.fa-sort-up:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-gavel:before,.fa-legal:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-bolt:before,.fa-flash:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-clipboard:before,.fa-paste:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-chain-broken:before,.fa-unlink:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:"\f150"}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:"\f151"}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:"\f152"}.fa-eur:before,.fa-euro:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-inr:before,.fa-rupee:before{content:"\f156"}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:"\f157"}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:"\f158"}.fa-krw:before,.fa-won:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-try:before,.fa-turkish-lira:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-bank:before,.fa-institution:before,.fa-university:before{content:"\f19c"}.fa-graduation-cap:before,.fa-mortar-board:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:"\f1c5"}.fa-file-archive-o:before,.fa-file-zip-o:before{content:"\f1c6"}.fa-file-audio-o:before,.fa-file-sound-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-empire:before,.fa-ge:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-paper-plane:before,.fa-send:before{content:"\f1d8"}.fa-paper-plane-o:before,.fa-send-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-bed:before,.fa-hotel:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-y-combinator:before,.fa-yc:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-television:before,.fa-tv:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"} -.displayBar{position:relative;width:236px;height:16px;border:1px solid #666;float:left;margin:0 5px 0 0;overflow:hidden;background:#000}.displayBarText{position:absolute;top:-2px;left:5px;width:100%;height:100%;color:#fff;font-weight:400}.displayBarFill{width:0;height:100%;background:#40628a;overflow:hidden;float:left}.displayBarFill.alignRight{float:right}.displayBarFill.good{color:#fff;background:#4f7529}.displayBarFill.notgood{color:#fff;background:#ffb400}.displayBarFill.average{color:#fff;background:#cd6500}.displayBarFill.bad{color:#fff;background:#e00}.displayBarFill.highlight{color:#fff;background:#8ba5c4}.disabled,.link,.linkOff,.linkOn,.redButton,.selected,.yellowButton{float:left;min-width:15px;height:16px;text-align:center;color:#fff;text-decoration:none;background:#40628a;border:1px solid #161616;padding:0 4px 4px;margin:0 2px 2px 0;cursor:default;white-space:nowrap}.hasIcon{padding:0 4px 4px 0}.linkActive:hover,.zoomLink:hover,a:hover{background:#507aac}.linkPending,.linkPending:hover{color:#fff;background:#507aac}a.white,a.white:active,a.white:link,a.white:visited{color:#40628a;text-decoration:none;background:#fff;border:1px solid #161616;padding:1px 4px;margin:0 2px 0 0;cursor:default}a.white:hover{color:#fff;background:#40628a}.linkOn,.selected,a.linkOn:active,a.linkOn:hover,a.linkOn:link,a.linkOn:visited,a.selected:active,a.selected:hover,a.selected:link,a.selected:visited{color:#fff;background:#2f943c}.disabled,.linkOff,a.disabled:active,a.disabled:hover,a.disabled:link,a.disabled:visited,a.linkOff:active,a.linkOff:hover,a.linkOff:link,a.linkOff:visited{color:#fff;background:#999;border-color:#666}.disabled.icon,.linkOff.icon,.linkOn.icon,.selected.icon,a.icon{position:relative;padding:1px 4px 2px 20px}.disabled.icon img,.linkOff.icon img,.linkOn.icon img,.selected.icon img,a.icon img{position:absolute;top:0;left:0;width:18px;height:18px}.linkDanger,a.linkDanger:active,a.linkDanger:link,a.linkDanger:visited{color:#fff;background-color:red;border-color:#a00}.linkDanger:hover{background-color:#f66}.inactive,a.inactive:active,a.inactive:hover,a.inactive:link,a.inactive:visited{color:#fff;background:#999;border-color:#666}.white{color:#fff}.good,.white{font-weight:700}.good{color:#4f7529}.average{color:#cd6500}.average,.bad{font-weight:700}.bad{color:#e00}.idle{color:#272727;font-weight:700}.redButton{background:#ea0000}.yellowButton{background:#cacc00}.highlight{color:#8ba5c4}.dark{color:#272727}.burn{color:orange}.brute{color:red}.toxin{color:green}.toxin_light{color:#3adf00}.oxyloss{color:blue}.oxyloss_light{color:#6698ff}.Red{color:red}.Blue{color:#00f}.Green{color:#0f0}.Marigold{color:#fda505}.Fuschia{color:#ff0080}.Black{color:#000}.Pearl{color:#c6cacb}.cold1{color:#94b8ff}.cold2{color:#69f}.cold3{color:#293d66}.hot1{color:#f96}.hot2{color:#993d00}.hot3{color:#f60}.itemGroup{border:1px solid #e9c183;background:#2c2c2c;padding:4px;clear:both}.item{width:100%;margin:4px 0 0;clear:both;overflow:auto}.itemContent,.itemContentNarrow{float:left}.itemContentNarrow{width:30%}.itemContent{width:69%}.itemLabel,.itemLabelNarrow,.itemLabelWide,.itemLabelWider,.itemLabelWidest{float:left;color:#e9c183}.itemLabelNarrow{width:20%}.itemLabel{width:30%}.itemLabelWide{width:45%}.itemLabelWider{width:69%}.itemLabelWidest{width:100%}.itemContentWide{float:left;width:79%}.itemContentSmall{float:left;width:33%}.itemContentMedium{float:left;width:55%}.block{padding:8px;margin:10px 4px 4px;border:1px solid #40628a;background-color:#202020}.block h3{padding:0}.clearBoth{clear:both}.clearLeft{clear:left}.clearRight{clear:right}.line{width:100%;clear:both}.fixedLeft{width:110px;float:left}.fixedLeftWide{width:165px;float:left}.fixedLeftWider{width:220px;float:left}.fixedLeftWidest{width:250px;float:left}.floatRight{float:right}.floatLeft{float:left}.hidden{display:none}.statusDisplay{overflow:hidden}.statusDisplay,.statusDisplayRecords{background:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#80000000,endColorStr=#80000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#80000000,endColorStr=#80000000);background:rgba(0,0,0,.5);color:#fff;border:1px solid #40628a;padding:4px;margin:3px 0}.statusDisplayRecords{overflow-x:hidden;overflow-y:auto}.statusLabel{width:138px;float:left;overflow:hidden;color:#98b0c3}.statusValue{float:left}.fancy{display:none}.minimize{color:#e9c183;position:absolute;top:6px;right:46px}.minimize:hover{color:#b8c9d6}.close{color:#e9c183;position:absolute;top:4px;right:12px}.close:hover{color:#b8c9d6}div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-style:solid;border-width:0 0 30px 30px;border-color:transparent transparent #363636;-webkit-transform:rotate(1turn);transform:rotate(1turn)}.uiLinkPendingIcon{display:none;float:left;width:16px;height:16px;margin:2px 2px 0;background-image:url(uiLinkPendingIcon.gif)}.linkPending .fa{display:none}.linkPending .uiLinkPendingIcon{display:block}.mapIcon16{position:absolute;width:16px;height:16px;background-image:url(uiIcons16Green.png);background-position:-144px -96px;background-repeat:no-repeat;zoom:.125;margin-left:-1px}.mapIcon16.bad,.mapIcon16.dead{background-image:url(uiIcons16Red.png)}.mapIcon16.average{background-image:url(uiIcons16Orange.png)}.mapIcon16.good{background-image:url(uiIcons16Green.png)}.mapIcon16.icon-airalarm{background-position:0 -144px}.mapIcon16.rank-captain{background-position:-224px -112px}.mapIcon16.rank-headofpersonnel{background-position:-112px -96px}.mapIcon16.rank-headofsecurity{background-position:-112px -128px}.mapIcon16.rank-chiefengineer{background-position:-176px -112px}.mapIcon16.rank-researchdirector{background-position:-128px -128px}.mapIcon16.rank-chiefmedicalofficer{background-position:-32px -128px}.mapIcon16.rank-atmospherictechnician,.mapIcon16.rank-stationengineer{background-position:-176px -112px}.mapIcon16.rank-chemist,.mapIcon16.rank-geneticist,.mapIcon16.rank-medicaldoctor,.mapIcon16.rank-psychiatrist{background-position:-32px -128px}.mapIcon16.rank-geneticist,.mapIcon16.rank-roboticist,.mapIcon16.rank-scientist,.mapIcon16.rank-xenobiologist{background-position:-128px -128px}.mapIcon16.rank-detective,.mapIcon16.rank-securityofficer,.mapIcon16.rank-warden{background-position:-112px -128px}ul{padding:4px 0 0 10px;margin:0;list-style-type:none}li{padding:0 0 2px}table.fixed{table-layout:fixed}table.fixed td{overflow:hidden}table.pmon{border:2px solid #4169e1}table.pmon td,table.pmon th{border-bottom:1px dotted #000;padding:0 5px}th.command{background:#33f}th.command,th.sec{font-weight:700;color:#fff}th.sec{background:#8e0000}th.med{background:#060}th.eng,th.med{font-weight:700;color:#fff}th.eng{background:#b27300}th.sci{background:#a65ba6}th.sci,th.ser{font-weight:700;color:#fff}th.ser{background:#7100aa}th.sup{background:#666621}th.civ,th.sup{font-weight:700;color:#fff}th.civ{background:#a32800}th.misc{background:#666;font-weight:700;color:#fff}span.qm-job{color:#b77a41;font-weight:700}.striped:not(table)>:nth-child(even),.striped tr:nth-child(even){background-color:#404040}#uiNoScript{position:fixed;top:50%;left:50%;margin:-60px 0 0 -150px;width:280px;height:120px;background:#fff;border:2px solid red;color:#000;font-size:10px;font-weight:700;z-index:1;padding:0 10px;text-align:center}.notice{background:url(uiNoticeBackground.jpg) 50% 50%;color:#000}.notice,.noticePlaceholder{position:relative;font-size:12px;font-style:italic;font-weight:700;padding:3px 4px;margin:4px 0}.notice.icon{padding:2px 4px 0 20px}.notice img{position:absolute;top:0;left:0;width:16px;height:16px}div.notice{clear:both}.wholeScreen{position:absolute;color:#517087;font-size:16px;font-weight:700;text-align:center}.pdalink{float:left;white-space:nowrap}.pdanote{color:#cd6500;font-weight:700}.dnaBlock{float:left;width:90px;padding:0 0 5px}.dnaBlockNumber{color:#fff;background:#363636;min-width:20px}.dnaBlockNumber,.dnaSubBlock{font-family:Fixed,monospace;float:left;height:20px;padding:0;text-align:center}.dnaSubBlock{min-width:16px}.mask{position:fixed;left:0;top:0;width:100%;height:100%;background:url(uiMaskBackground.png)}.maskContent{width:100%;height:200px;margin:200px 0;text-align:center}body{background:#272727;color:#fff;font-family:Verdana,Geneva,sans-serif;font-size:12px;line-height:170%;margin:0;padding:0}hr{background-color:#40628a;height:1px;border:none}a img,img{border-style:none}h1,h2,h3,h4,h5,h6{margin:0;padding:12px 0 6px;color:#fff;clear:both}h1{font-size:18px}h2{font-size:16px}h3{font-size:14px}h4{font-size:12px}body{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' version='1' viewBox='0 0 425 200' opacity='.25'%3E%3Cpath d='M178.004.04H106.8a6.76 6.026 0 0 0-6.76 6.024v187.872a6.76 6.026 0 0 0 6.76 6.025h53.107a6.76 6.026 0 0 0 6.762-6.024V92.392l72.215 104.7a6.76 6.026 0 0 0 5.76 2.87H318.2a6.76 6.026 0 0 0 6.76-6.026V6.064A6.76 6.026 0 0 0 318.2.04h-54.717a6.76 6.026 0 0 0-6.76 6.024v102.62L183.762 2.91a6.76 6.026 0 0 0-5.76-2.87zM4.845 22.11A13.412 12.502 0 0 1 13.478.04h66.118a5.365 5 0 0 1 5.365 5v79.88zM420.155 177.89a13.412 12.502 0 0 1-8.633 22.07h-66.118a5.365 5 0 0 1-5.365-5v-79.88z'/%3E%3C/svg%3E") no-repeat fixed center/70% 70%,linear-gradient(180deg,#2a2a2a 0,#202020) no-repeat fixed center/100% 100%;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff2a2a2a',endColorstr='#ff000000',GradientType=0)}#uiWrapper{width:100%;height:100%;-ms-user-select:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}#uiTitleWrapper{position:relative;height:30px}#uiTitleText{position:absolute;top:6px;left:44px;width:66%;overflow:hidden;color:#e9c183;font-size:16px}#uiTitle.icon{padding:6px 8px 6px 42px;background-position:2px 50%;background-repeat:no-repeat}#uiTitleFluff{position:absolute;top:4px;right:12px;width:42px;height:24px;background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' version='1' viewBox='0 0 425 200' opacity='.25'%3E%3Cpath d='M178.004.04H106.8a6.76 6.026 0 0 0-6.76 6.024v187.872a6.76 6.026 0 0 0 6.76 6.025h53.107a6.76 6.026 0 0 0 6.762-6.024V92.392l72.215 104.7a6.76 6.026 0 0 0 5.76 2.87H318.2a6.76 6.026 0 0 0 6.76-6.026V6.064A6.76 6.026 0 0 0 318.2.04h-54.717a6.76 6.026 0 0 0-6.76 6.024v102.62L183.762 2.91a6.76 6.026 0 0 0-5.76-2.87zM4.845 22.11A13.412 12.502 0 0 1 13.478.04h66.118a5.365 5 0 0 1 5.365 5v79.88zM420.155 177.89a13.412 12.502 0 0 1-8.633 22.07h-66.118a5.365 5 0 0 1-5.365-5v-79.88z'/%3E%3C/svg%3E") 50% 50% no-repeat}.statusicon{position:absolute;top:4px;left:12px}#uiMapWrapper{clear:both;padding:8px}#uiMapHeader{position:relative;clear:both}#uiMapContainer{position:relative;width:100%;height:600px;overflow:hidden;border:1px solid #40628a;background:url(nanomapBackground.png)}#uiMap{top:50%;left:50%;margin:-512px 0 0 -512px;overflow:hidden;zoom:4}#uiMap,#uiMapImage{position:absolute;width:256px;height:256px}#uiMapImage{bottom:1px;left:1px}#uiMapContent{position:absolute;bottom:-13.5px;left:0;width:256px;height:256px}#uiMapFooter{position:relative;clear:both}#uiContent{clear:both;padding:8px}#uiMapTooltip{position:absolute;right:10px;top:10px;border:1px solid #40628a;background-color:#272727;padding:8px;display:none;z-index:1}#uiLoadingNotice{position:relative;background:url(uiNoticeBackground.jpg) 50% 50%;color:#000;font-size:14px;font-style:italic;font-weight:700;padding:3px 4px;margin:4px 0} \ No newline at end of file +.displayBar{position:relative;width:236px;height:16px;border:1px solid #666;float:left;margin:0 5px 0 0;overflow:hidden;background:#000}.displayBarText{position:absolute;top:-2px;left:5px;width:100%;height:100%;color:#fff;font-weight:400}.displayBarFill{width:0;height:100%;background:#40628a;overflow:hidden;float:left}.displayBarFill.alignRight{float:right}.displayBarFill.good{color:#fff;background:#4f7529}.displayBarFill.notgood{color:#fff;background:#ffb400}.displayBarFill.average{color:#fff;background:#cd6500}.displayBarFill.bad{color:#fff;background:#e00}.displayBarFill.highlight{color:#fff;background:#8ba5c4}.disabled,.link,.linkOff,.linkOn,.redButton,.selected,.yellowButton{float:left;min-width:15px;height:16px;text-align:center;color:#fff;text-decoration:none;background:#40628a;border:1px solid #161616;padding:0 4px 4px;margin:0 2px 2px 0;cursor:default;white-space:nowrap}.hasIcon{padding:0 4px 4px 0}.linkActive:hover,.zoomLink:hover,a:hover{background:#507aac}.linkPending,.linkPending:hover{color:#fff;background:#507aac}a.white,a.white:active,a.white:link,a.white:visited{color:#40628a;text-decoration:none;background:#fff;border:1px solid #161616;padding:1px 4px;margin:0 2px 0 0;cursor:default}a.white:hover{color:#fff;background:#40628a}.linkOn,.selected,a.linkOn:active,a.linkOn:hover,a.linkOn:link,a.linkOn:visited,a.selected:active,a.selected:hover,a.selected:link,a.selected:visited{color:#fff;background:#2f943c}.disabled,.linkOff,a.disabled:active,a.disabled:hover,a.disabled:link,a.disabled:visited,a.linkOff:active,a.linkOff:hover,a.linkOff:link,a.linkOff:visited{color:#fff;background:#999;border-color:#666}.disabled.icon,.linkOff.icon,.linkOn.icon,.selected.icon,a.icon{position:relative;padding:1px 4px 2px 20px}.disabled.icon img,.linkOff.icon img,.linkOn.icon img,.selected.icon img,a.icon img{position:absolute;top:0;left:0;width:18px;height:18px}.linkDanger,a.linkDanger:active,a.linkDanger:link,a.linkDanger:visited{color:#fff;background-color:red;border-color:#a00}.linkDanger:hover{background-color:#f66}.inactive,a.inactive:active,a.inactive:hover,a.inactive:link,a.inactive:visited{color:#fff;background:#999;border-color:#666}.white{color:#fff}.good,.white{font-weight:700}.good{color:#4f7529}.average{color:#cd6500}.average,.bad{font-weight:700}.bad{color:#e00}.idle{color:#272727;font-weight:700}.redButton{background:#ea0000}.yellowButton{background:#cacc00}.highlight{color:#8ba5c4}.dark{color:#272727}.burn{color:orange}.brute{color:red}.toxin{color:green}.toxin_light{color:#3adf00}.oxyloss{color:blue}.oxyloss_light{color:#6698ff}.Red{color:red}.Blue{color:#00f}.Green{color:#0f0}.Marigold{color:#fda505}.Fuschia{color:#ff0080}.Black{color:#000}.Pearl{color:#c6cacb}.cold1{color:#94b8ff}.cold2{color:#69f}.cold3{color:#293d66}.hot1{color:#f96}.hot2{color:#993d00}.hot3{color:#f60}.itemGroup{border:1px solid #e9c183;background:#2c2c2c;padding:4px;clear:both}.item{width:100%;margin:4px 0 0;clear:both;overflow:auto}.itemContent,.itemContentNarrow{float:left}.itemContentNarrow{width:30%}.itemContent{width:69%}.itemLabel,.itemLabelNarrow,.itemLabelWide,.itemLabelWider,.itemLabelWidest{float:left;color:#e9c183}.itemLabelNarrow{width:20%}.itemLabel{width:30%}.itemLabelWide{width:45%}.itemLabelWider{width:69%}.itemLabelWidest{width:100%}.itemContentWide{float:left;width:79%}.itemContentSmall{float:left;width:33%}.itemContentMedium{float:left;width:55%}.block{padding:8px;margin:10px 4px 4px;border:1px solid #40628a;background-color:#202020}.block h3{padding:0}.clearBoth{clear:both}.clearLeft{clear:left}.clearRight{clear:right}.line{width:100%;clear:both}.fixedLeft{width:110px;float:left}.fixedLeftWide{width:165px;float:left}.fixedLeftWider{width:220px;float:left}.fixedLeftWidest{width:250px;float:left}.floatRight{float:right}.floatLeft{float:left}.hidden{display:none}.statusDisplay{overflow:hidden}.statusDisplay,.statusDisplayRecords{background:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#80000000,endColorStr=#80000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#80000000,endColorStr=#80000000);background:rgba(0,0,0,.5);color:#fff;border:1px solid #40628a;padding:4px;margin:3px 0}.statusDisplayRecords{overflow-x:hidden;overflow-y:auto}.statusLabel{width:138px;float:left;overflow:hidden;color:#98b0c3}.statusValue{float:left}.fancy{display:none}.minimize{color:#e9c183;position:absolute;top:6px;right:46px}.minimize:hover{color:#b8c9d6}.close{color:#e9c183;position:absolute;top:4px;right:12px}.close:hover{color:#b8c9d6}div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-style:solid;border-width:0 0 30px 30px;border-color:transparent transparent #363636;-webkit-transform:rotate(1turn);transform:rotate(1turn)}.uiLinkPendingIcon{display:none;float:left;width:16px;height:16px;margin:2px 2px 0;background-image:url(uiLinkPendingIcon.gif)}.linkPending .fa{display:none}.linkPending .uiLinkPendingIcon{display:block}.mapIcon16{position:absolute;width:16px;height:16px;background-image:url(uiIcons16Green.png);background-position:-144px -96px;background-repeat:no-repeat;zoom:.125;margin-left:-1px}.mapIcon16.bad,.mapIcon16.dead{background-image:url(uiIcons16Red.png)}.mapIcon16.average{background-image:url(uiIcons16Orange.png)}.mapIcon16.good{background-image:url(uiIcons16Green.png)}.mapIcon16.icon-airalarm{background-position:0 -144px}.mapIcon16.rank-captain{background-position:-224px -112px}.mapIcon16.rank-headofpersonnel{background-position:-112px -96px}.mapIcon16.rank-headofsecurity{background-position:-112px -128px}.mapIcon16.rank-chiefengineer{background-position:-176px -112px}.mapIcon16.rank-researchdirector{background-position:-128px -128px}.mapIcon16.rank-chiefmedicalofficer{background-position:-32px -128px}.mapIcon16.rank-atmospherictechnician,.mapIcon16.rank-stationengineer{background-position:-176px -112px}.mapIcon16.rank-chemist,.mapIcon16.rank-geneticist,.mapIcon16.rank-medicaldoctor,.mapIcon16.rank-psychiatrist{background-position:-32px -128px}.mapIcon16.rank-geneticist,.mapIcon16.rank-roboticist,.mapIcon16.rank-scientist,.mapIcon16.rank-xenobiologist{background-position:-128px -128px}.mapIcon16.rank-detective,.mapIcon16.rank-securityofficer,.mapIcon16.rank-warden{background-position:-112px -128px}ul{padding:4px 0 0 10px;margin:0;list-style-type:none}li{padding:0 0 2px}table.fixed{table-layout:fixed}table.fixed td{overflow:hidden}table.pmon{border:2px solid #4169e1}table.pmon td,table.pmon th{border-bottom:1px dotted #000;padding:0 5px}th.command{background:#33f}th.command,th.sec{font-weight:700;color:#fff}th.sec{background:#8e0000}th.med{background:#060}th.eng,th.med{font-weight:700;color:#fff}th.eng{background:#b27300}th.sci{background:#a65ba6}th.sci,th.ser{font-weight:700;color:#fff}th.ser{background:#7100aa}th.sup{background:#666621}th.civ,th.sup{font-weight:700;color:#fff}th.civ{background:#a32800}th.misc{background:#666;font-weight:700;color:#fff}span.qm-job{color:#b77a41;font-weight:700}.striped:not(table)>:nth-child(even),.striped tr:nth-child(even){background-color:#404040}#uiNoScript{position:fixed;top:50%;left:50%;margin:-60px 0 0 -150px;width:280px;height:120px;background:#fff;border:2px solid red;color:#000;font-size:10px;font-weight:700;z-index:1;padding:0 10px;text-align:center}.notice{background:url(uiNoticeBackground.jpg) 50% 50%;color:#000}.notice,.noticePlaceholder{position:relative;font-size:12px;font-style:italic;font-weight:700;padding:3px 4px;margin:4px 0}.notice.icon{padding:2px 4px 0 20px}.notice img{position:absolute;top:0;left:0;width:16px;height:16px}div.notice{clear:both}.wholeScreen{position:absolute;color:#517087;font-size:16px;font-weight:700;text-align:center}.pdalink{float:left;white-space:nowrap;cursor:default!important}.pdalink.disabled{background:none;border:none;color:#999;text-align:left}.pdanote{color:#cd6500;font-weight:700}.item.mainmenu{padding-bottom:.5em}div.clock{color:#fff;font-weight:700;float:right;padding-right:2em}#pdaFooter{position:fixed;left:0;bottom:0;width:100%;background:#272727}.pdaFooterButton{width:33%;padding:.5em 0;font-size:200%;border:none;background:none;color:#fff}.pdaFooterButton:hover{background:#507aac}.pdaFooterButton.disabled{background:none!important;color:#555!important}.pdaFooterButton .uiLinkPendingIcon{position:absolute;width:33%;background-repeat:no-repeat;background-position:center}.dnaBlock{float:left;width:90px;padding:0 0 5px}.dnaBlockNumber{color:#fff;background:#363636;min-width:20px}.dnaBlockNumber,.dnaSubBlock{font-family:Fixed,monospace;float:left;height:20px;padding:0;text-align:center}.dnaSubBlock{min-width:16px}.mask{position:fixed;left:0;top:0;width:100%;height:100%;background:url(uiMaskBackground.png)}.maskContent{width:100%;height:200px;margin:200px 0;text-align:center}body{background:#272727;color:#fff;font-family:Verdana,Geneva,sans-serif;font-size:12px;line-height:170%;margin:0;padding:0}hr{background-color:#40628a;height:1px;border:none}a img,img{border-style:none}h1,h2,h3,h4,h5,h6{margin:0;padding:12px 0 6px;color:#fff;clear:both}h1{font-size:18px}h2{font-size:16px}h3{font-size:14px}h4{font-size:12px}body{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' version='1' viewBox='0 0 425 200' opacity='.25'%3E%3Cpath d='M178.004.04H106.8a6.76 6.026 0 0 0-6.76 6.024v187.872a6.76 6.026 0 0 0 6.76 6.025h53.107a6.76 6.026 0 0 0 6.762-6.024V92.392l72.215 104.7a6.76 6.026 0 0 0 5.76 2.87H318.2a6.76 6.026 0 0 0 6.76-6.026V6.064A6.76 6.026 0 0 0 318.2.04h-54.717a6.76 6.026 0 0 0-6.76 6.024v102.62L183.762 2.91a6.76 6.026 0 0 0-5.76-2.87zM4.845 22.11A13.412 12.502 0 0 1 13.478.04h66.118a5.365 5 0 0 1 5.365 5v79.88zM420.155 177.89a13.412 12.502 0 0 1-8.633 22.07h-66.118a5.365 5 0 0 1-5.365-5v-79.88z'/%3E%3C/svg%3E") no-repeat fixed center/70% 70%,linear-gradient(180deg,#2a2a2a 0,#202020) no-repeat fixed center/100% 100%;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff2a2a2a',endColorstr='#ff000000',GradientType=0)}#uiWrapper{width:100%;height:100%;-ms-user-select:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}#uiTitleWrapper{position:relative;height:30px}#uiTitleText{position:absolute;top:6px;left:44px;width:66%;overflow:hidden;color:#e9c183;font-size:16px}#uiTitle.icon{padding:6px 8px 6px 42px;background-position:2px 50%;background-repeat:no-repeat}#uiTitleFluff{position:absolute;top:4px;right:12px;width:42px;height:24px;background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' version='1' viewBox='0 0 425 200' opacity='.25'%3E%3Cpath d='M178.004.04H106.8a6.76 6.026 0 0 0-6.76 6.024v187.872a6.76 6.026 0 0 0 6.76 6.025h53.107a6.76 6.026 0 0 0 6.762-6.024V92.392l72.215 104.7a6.76 6.026 0 0 0 5.76 2.87H318.2a6.76 6.026 0 0 0 6.76-6.026V6.064A6.76 6.026 0 0 0 318.2.04h-54.717a6.76 6.026 0 0 0-6.76 6.024v102.62L183.762 2.91a6.76 6.026 0 0 0-5.76-2.87zM4.845 22.11A13.412 12.502 0 0 1 13.478.04h66.118a5.365 5 0 0 1 5.365 5v79.88zM420.155 177.89a13.412 12.502 0 0 1-8.633 22.07h-66.118a5.365 5 0 0 1-5.365-5v-79.88z'/%3E%3C/svg%3E") 50% 50% no-repeat}.statusicon{position:absolute;top:4px;left:12px}#uiMapWrapper{clear:both;padding:8px}#uiMapHeader{position:relative;clear:both}#uiMapContainer{position:relative;width:100%;height:600px;overflow:hidden;border:1px solid #40628a;background:url(nanomapBackground.png)}#uiMap{top:50%;left:50%;margin:-512px 0 0 -512px;overflow:hidden;zoom:4}#uiMap,#uiMapImage{position:absolute;width:256px;height:256px}#uiMapImage{bottom:1px;left:1px}#uiMapContent{position:absolute;bottom:-13.5px;left:0;width:256px;height:256px}#uiMapFooter{position:relative;clear:both}#uiContent{clear:both;padding:8px}#uiMapTooltip{position:absolute;right:10px;top:10px;border:1px solid #40628a;background-color:#272727;padding:8px;display:none;z-index:1}#uiLoadingNotice{position:relative;background:url(uiNoticeBackground.jpg) 50% 50%;color:#000;font-size:14px;font-style:italic;font-weight:700;padding:3px 4px;margin:4px 0} \ No newline at end of file diff --git a/nano/scripts/nano/nano_state_pda.js b/nano/scripts/nano/nano_state_pda.js new file mode 100644 index 00000000000..13135046caf --- /dev/null +++ b/nano/scripts/nano/nano_state_pda.js @@ -0,0 +1,58 @@ +NanoStatePDAClass.inheritsFrom(NanoStateClass); +var NanoStatePDA = new NanoStatePDAClass(); + +function NanoStatePDAClass() { + this.key = 'pda'; + this.key = this.key.toLowerCase(); + this.current_template = ""; + + NanoStateManager.addState(this); +} + +NanoStatePDAClass.prototype.onUpdate = function(data) { + NanoStateClass.prototype.onUpdate.call(this, data); + var state = this; + + try { + if(data['data']['app'] != null) { + var template = data['data']['app']['template']; + if(template != null && template != state.current_template) { + $.when($.ajax({ + url: template + '.tmpl', + cache: false, + dataType: 'text' + })) + .done(function(templateMarkup) { + templateMarkup += '
    '; + + try { + NanoTemplate.addTemplate('app', templateMarkup); + NanoTemplate.resetTemplate('app'); + $("#uiApp").html(NanoTemplate.parse('app', data)); + state.current_template = template; + + if(data['config']['status'] == 2) { + $('#uiApp .linkActive').addClass('linkPending'); + $('#uiApp .linkActive').oneTime(400, 'linkPending', function () { + $('#uiApp .linkActive').removeClass('linkPending inactive'); + }); + } + } catch(error) { + reportError('ERROR: An error occurred while loading the PDA App UI: ' + error.message); + return; + } + }) + .fail( function () { + reportError('ERROR: Loading template app(' + template + ') failed!'); + }); + } else { + if (NanoTemplate.templateExists('app')) { + $("#uiApp").html(NanoTemplate.parse('app', data)); + } + } + } + } catch(error) { + reportError('ERROR: An error occurred while rendering the PDA App UI: ' + error.message); + return; + } +} \ No newline at end of file diff --git a/nano/scripts/nano/nano_template.js b/nano/scripts/nano/nano_template.js index 7350e62d48d..e37724f1bb4 100644 --- a/nano/scripts/nano/nano_template.js +++ b/nano/scripts/nano/nano_template.js @@ -87,6 +87,9 @@ var NanoTemplate = function () { templateExists: function (key) { return _templates.hasOwnProperty(key); }, + resetTemplate: function (key) { + _compiledTemplates[key] = null; + }, parse: function (templateKey, data) { if (!_compiledTemplates.hasOwnProperty(templateKey) || !_compiledTemplates[templateKey]) { if (!_templates.hasOwnProperty(templateKey)) { diff --git a/nano/styles/_color.less b/nano/styles/_color.less index 6194a96ac2b..68fc1d89c5b 100644 --- a/nano/styles/_color.less +++ b/nano/styles/_color.less @@ -1,9 +1,4 @@ -@good-color: #4f7529; -@average-color: #cd6500; -@bad-color: #ee0000; - -@highlight-color: #8BA5C4; -@dark-color: #272727; +@import "_config"; .white { color: white; diff --git a/nano/styles/_config.less b/nano/styles/_config.less index a44ef50fd54..dffcc37331c 100644 --- a/nano/styles/_config.less +++ b/nano/styles/_config.less @@ -4,4 +4,12 @@ // Body Colors @background-start: #2a2a2a; -@background-end: #202020; \ No newline at end of file +@background-end: #202020; + +// Element Colors +@good-color: #4f7529; +@average-color: #cd6500; +@bad-color: #ee0000; + +@highlight-color: #8BA5C4; +@dark-color: #272727; \ No newline at end of file diff --git a/nano/styles/_misc.less b/nano/styles/_misc.less index 55f8216b3b6..fe7646062b2 100644 --- a/nano/styles/_misc.less +++ b/nano/styles/_misc.less @@ -74,6 +74,14 @@ div.notice { .pdalink { float: left; white-space: nowrap; + cursor: default !important; + + &.disabled { + background: none; + border: none; + color: #999; + text-align: left; + } } .pdanote { @@ -81,6 +89,50 @@ div.notice { font-weight: bold; } +.item.mainmenu { + padding-bottom: 0.5em; +} + +div.clock { + color: white; + font-weight: bold; + float: right; + padding-right: 2em; +} + +#pdaFooter { + position: fixed; + left: 0; + bottom: 0; + width: 100%; + background: @dark-color; +} + +.pdaFooterButton { + width: 33%; + padding: 0.5em 0; + font-size: 200%; + border: none; + background: none; + color: #fff; + + &:hover { + background: #507aac; + } + + &.disabled { + background: none !important; + color: #555 !important; + } + + .uiLinkPendingIcon { + position: absolute; + width: 33%; + background-repeat: no-repeat; + background-position: center; + } +} + /* DNA Modifier styling */ .dnaBlock { float: left; diff --git a/nano/styles/_native.less b/nano/styles/_native.less index 8114d75133c..3061b54c72c 100644 --- a/nano/styles/_native.less +++ b/nano/styles/_native.less @@ -1,7 +1,7 @@ @import "_config"; body { - background: #272727; + background: @dark-color; color: #ffffff; font-family: @font; font-size: @fontsize; diff --git a/nano/templates/pda.tmpl b/nano/templates/pda.tmpl index 54ab77a9be6..3d11ee0a6f8 100644 --- a/nano/templates/pda.tmpl +++ b/nano/templates/pda.tmpl @@ -1,4 +1,3 @@ - - {{:helper.link('Close', 'gear', {'choice' : "Close"}, null, 'pdalink fixedLeft')}} - {{if data.idInserted}} {{:helper.link('Update PDA Info', 'eject', {'choice' : "UpdateInfo"}, null, 'pdalink fixedLeftWide')}} {{/if}} - {{if data.mode != 0}} {{:helper.link('Return', 'arrow-left', {'choice' : "Return"}, null, 'pdalink fixedLeft')}} {{/if}} - {{:helper.link('Toggle R.E.T.R.O. mode', 'gear', {'choice': "Retro"}, null, 'floatRight')}} +
    + {{if data.idInserted}} + {{:helper.link(data.idLink, 'eject', {'choice' : "Authenticate"}, null, 'pdalink fixedLeftWide')}} + {{/if}} + {{if data.cartridge_name}} + {{:helper.link(data.cartridge_name, 'eject', {'choice' : "Eject"}, null, 'pdalink fixedLeftWidest')}} + {{/if}} + {{:helper.link('Toggle R.E.T.R.O. mode', 'gear', {'choice': "Retro"}, null, 'pdalink fixedLeftWide')}} +
    +
    + {{:data.stationTime}}
    -
    -
    -
    - Station Time: -
    -
    - {{:data.stationTime}} -
    + + {{if data.app}} +

     {{:data.app.name}}

    +
    +
     
    + {{/if}} + +
    + {{:helper.link("", 'undo', {'choice' : "Back"}, data.app.has_back ? null : 'disabled', 'link pdaFooterButton')}} + {{:helper.link("", 'home', {'choice' : "Home"}, data.app.is_home ? 'disabled' : null, 'link pdaFooterButton')}}
    -
    - - - {{if data.mode == 0}} -
    -
    - Owner: -
    -
    - {{:data.owner}}, {{:data.ownjob}} -
    -
    -
    -
    -
    - ID: -
    -
    - {{:helper.link(data.idLink, 'eject', {'choice' : "Authenticate"}, data.idInserted ? null : 'disabled', data.idInserted ? 'link fixedLeftWidest' : 'link fixedLeft')}} -
    -
    -
    -
    -
    - Cartridge: -
    -
    - {{if data.cart_loaded==1}} - {{:helper.link(data.cartridge.name, 'eject', {'choice' : "Eject"},null,null)}} - {{else}} - {{:helper.link('None', 'eject', {'choice' : "Eject"},'disabled',null)}} - {{/if}} -
    -
    -
    -

    Functions

    -
    -
    -
    - General: -
    -
    - {{:helper.link('Notekeeper', 'sticky-note', {'choice' : "1"}, null, 'pdalink fixedLeftWide')}} - {{:helper.link('Messenger', data.newMessage ? 'envelope' : 'envelope-o', {'choice' : "2"}, null, 'pdalink fixedLeftWide')}} - {{:helper.link('Crew Manifest', 'user', {'choice' : "41"}, null, 'pdalink fixedLeftWide')}} -
    -
    -
    - {{if data.cartridge}} - {{if data.cartridge.access.access_clown == 1}} -
    -
    - Clown: -
    -
    - {{:helper.link('Honk Synthesizer', 'gear', {'choice' : "Honk"}, null, 'pdalink fixedLeftWide')}} -
    -
    -
    - {{/if}} - {{if data.cartridge.access.access_engine == 1}} -
    -
    - Engineering: -
    -
    - {{:helper.link('Power Monitor', 'exclamation-triangle', {'choice' : "43"}, null, 'pdalink fixedLeftWide')}} -
    -
    -
    - {{/if}} - {{if data.cartridge.access.access_medical == 1}} -
    -
    - Medical: -
    -
    - {{:helper.link('Medical Records', 'gear', {'choice' : "44"}, null, 'pdalink fixedLeftWide')}} - {{:helper.link(data.scanmode == 1 ? 'Disable Med Scanner' : 'Enable Med Scanner', 'gear', {'choice' : "Medical Scan"}, null , 'pdalink fixedLeftWide')}} -
    -
    -
    - {{/if}} - {{if data.cartridge.access.access_security == 1}} -
    -
    - Security: -
    -
    - {{:helper.link('Security Records', 'gear', {'choice' : "45"}, null, 'pdalink fixedLeftWide')}} - {{if data.cartridge.radio ==1}} {{:helper.link('Security Bot Access', 'gear', {'choice' : "46"}, null, 'pdalink fixedLeftWide')}} {{/if}} -
    -
    -
    -
    - {{/if}} - {{if data.cartridge.access.access_quartermaster == 1}} -
    -
    - Quartermaster: -
    -
    - {{:helper.link('Supply Records', 'gear', {'choice' : "47"}, null, 'pdalink fixedLeftWide')}} - {{if data.cartridge.radio == 3}} {{:helper.link('Delivery Bot Control', 'gear', {'choice' : "48"}, null, 'pdalink fixedLeftWide')}} {{/if}} -
    -
    -
    -
    - {{/if}} - {{/if}} -
    -
    -
    - Utilities: -
    -
    - {{if data.cartridge}} - {{if data.cartridge.access.access_status_display == 1}} - {{:helper.link('Status Display', 'gear', {'choice' : "42"}, null, 'pdalink fixedLeftWide')}} - {{/if}} - {{if data.cartridge.access.access_janitor==1}} - {{:helper.link('Custodial Locator', 'gear', {'choice' : "49"}, null, 'pdalink fixedLeftWide')}} - {{/if}} - {{if data.cartridge.radio == 2}} - {{:helper.link('Signaler System', 'gear', {'choice' : "40"}, null, 'pdalink fixedLeftWide')}} - {{/if}} - {{if data.cartridge.access.access_reagent_scanner==1}} - {{:helper.link(data.scanmode == 3 ? 'Disable Reagent Scanner' : 'Enable Reagent Scanner', 'gear', {'choice' : "Reagent Scan"}, null, 'pdalink fixedLeftWider')}} - {{/if}} - {{if data.cartridge.access.access_engine==1}} - {{:helper.link(data.scanmode == 4 ? 'Disable Halogen Counter' : 'Enable Halogen Counter', 'gear', {'choice' : "Halogen Counter"}, null, 'pdalink fixedLeftWider')}} - {{/if}} - {{if data.cartridge.access.access_atmos==1}} - {{:helper.link(data.scanmode == 5 ? 'Disable Gas Scanner' : 'Enable Gas Scanner', 'gear', {'choice' : "Gas Scan"}, null, 'pdalink fixedLeftWide')}} - {{/if}} - {{if data.cartridge.access.access_remote_door==1}} - {{:helper.link('Toggle Door', 'gear', {'choice' : "Toggle Door"}, null, 'pdalink fixedLeftWide')}} - {{/if}} - {{/if}} - {{:helper.link('Atmospheric Scan', 'gear', {'choice' : "3"}, null, 'pdalink fixedLeftWide')}} - {{:helper.link(data.fon==1 ? 'Disable Flashlight' : 'Enable Flashlight', 'lightbulb-o', {'choice' : "Light"}, null,'pdalink fixedLeftWide')}} -
    -
    - {{if data.pai}} -
    -
    - PAI Utilities: -
    -
    - {{:helper.link('Configuration', 'gear', {'choice' : "pai", 'option' : "1"}, null, 'pdalink fixedLeft')}} - {{:helper.link('Eject pAI', 'eject', {'choice' : "pai", 'option' : "2"}, null, 'pdalink fixedLeft')}} -
    -
    - {{/if}} - - - {{else data.mode == 1}} -
    -
    - Notes: -
    -
    -
    -
    -
    - {{:data.note}} -
    -
    -
    -
    -
    - {{:helper.link('Edit Notes', 'gear', {'choice' : "Edit"}, null, 'pdalink fixedLeft')}} -
    -
    - - - {{else data.mode == 2}} -

    SpaceMessenger V4.0.1

    -
    -
    - Messenger Functions: -
    -
    - {{:helper.link(data.silent==1 ? 'Ringer: Off' : 'Ringer: On', data.silent==1 ? 'volume-off' : 'volume-up', {'choice' : "Toggle Ringer"}, null, 'pdalink fixedLeftWide')}} - {{:helper.link(data.toff==1 ? 'Messenger: Off' : 'Messenger: On',data.toff==1 ? 'close':'check', {'choice' : "Toggle Messenger"}, null, 'pdalink fixedLeftWide')}} - {{:helper.link('Set Ringtone', 'comment', {'choice' : "Ringtone"}, null, 'pdalink fixedLeftWide')}} - {{:helper.link('Delete all Conversations', 'trash', {'choice' : "Clear", 'option' : "All"}, null, 'pdalink fixedLeftWider')}} -
    -
    - {{if data.toff == 0}} -

    - {{if data.cartridge}} - {{if data.cartridge.charges}} -
    - {{:data.cartridge.charges}} - {{if data.cartridge.access.access_detonate_pda}} detonation charges left. {{/if}} - {{if data.cartridge.access.access_clown || data.cartridge.access.access_mime}} viral files left. {{/if}} - -

    -
    - {{/if}} - {{/if}} - - {{if data.pda_count == 0}} - No other PDAS located - {{else}} -

    Current Conversations

    - {{for data.convopdas}} -
    - {{:helper.link(value.Name, 'arrow-circle-down', {'choice' : "Select Conversation", 'convo' : value.Reference } , null, 'pdalink')}} - {{if data.cartridge}} - {{if data.cartridge.access.access_detonate_pda && value.Detonate}} - {{:helper.link('*Detonate*', 'exclamation-circle', {'choice' : "Detonate", 'target' : value.Reference}, null, 'pdalink fixedLeft')}} - {{/if}} - {{if data.cartridge.access.access_clown}} - {{:helper.link('*Send Virus*', 'star', {'choice' : "Send Honk", 'target' : value.Reference}, null, 'pdalink fixedLeft')}} - {{/if}} - {{if data.cartridge.access.access_mime}} - {{:helper.link('*Send Virus*', 'arrow-circle-down', {'choice' : "Send Silence", 'target' : value.Reference}, null, 'pdalink fixedLeft')}} - {{/if}} - {{/if}} -
    - {{/for}} -

    Other PDAs

    - {{for data.pdas}} -
    - {{:helper.link(value.Name, 'arrow-circle-down', {'choice' : "Message", 'target' : value.Reference}, null, 'pdalink')}} - {{if data.cartridge}} - {{if data.cartridge.access.access_detonate_pda && value.Detonate}} {{:helper.link('*Detonate*', 'exclamation-circle', {'choice' : "Detonate", 'target' : value.Reference}, null, 'pdalink fixedLeft')}} {{/if}} - {{if data.cartridge.access.access_clown}} {{:helper.link('*Send Virus*', 'star', {'choice' : "Send Honk", 'target' : value.Reference}, null, 'pdalink fixedLeft')}} {{/if}} - {{if data.cartridge.access.access_mime}} {{:helper.link('*Send Virus*', 'arrow-circle-down', {'choice' : "Send Silence", 'target' : value.Reference}, null, 'pdalink fixedLeft')}} {{/if}} - {{/if}} -
    - {{/for}} - {{/if}} - {{/if}} - - - {{else data.mode == 21}} -

    SpaceMessenger V4.0.1

    -
    -
    - Messenger Functions: -
    -
    - {{:helper.link('Delete Conversation', 'trash', {'choice' : "Clear", 'option' : "Convo"}, null, 'pdalink fixedLeftWide')}} -
    -
    -
    -
    -

    Conversation with: {{:data.convo_name}} ({{:data.convo_job}})

    -
    -
    -
    - {{for data.messages}} - {{if data.active_conversation == value.target}} - {{if value.sent==0}} - Them: {{:value.message}}
    - {{else}} - You: {{:value.message}}
    - {{/if}} - {{/if}} - {{/for}} -
    -
    -
    - {{:helper.link('Reply', 'comment', {'choice' : "Message", 'target': data.active_conversation}, null, 'pdalink fixedLeft')}} - - - {{else data.mode== 41}} -
    -
    - {{if data.manifest.heads}} - - {{for data.manifest["heads"]}} - {{if value.rank == "Captain"}} - - {{else}} - - {{/if}} - {{/for}} - {{/if}} - {{if data.manifest.sec}} - - {{for data.manifest["sec"]}} - {{if value.rank == "Head of Security"}} - - {{else}} - - {{/if}} - {{/for}} - {{/if}} - {{if data.manifest.eng}} - - {{for data.manifest["eng"]}} - {{if value.rank == "Chief Engineer"}} - - {{else}} - - {{/if}} - {{/for}} - {{/if}} - {{if data.manifest.med}} - - {{for data.manifest["med"]}} - {{if value.rank == "Chief Medical Officer"}} - - {{else}} - - {{/if}} - {{/for}} - {{/if}} - {{if data.manifest.sci}} - - {{for data.manifest["sci"]}} - {{if value.rank == "Research Director"}} - - {{else}} - - {{/if}} - {{/for}} - {{/if}} - {{if data.manifest.ser}} - - {{for data.manifest["ser"]}} - {{if value.rank == "Head of Personnel"}} - - {{else}} - - {{/if}} - {{/for}} - {{/if}} - {{if data.manifest.sup}} - - {{for data.manifest["sup"]}} - {{if value.rank == "Head of Personnel"}} - - {{else value.rank == "Quartermaster"}} - - {{else}} - - {{/if}} - {{/for}} - {{/if}} - {{if data.manifest.civ}} - - {{for data.manifest["civ"]}} - {{if value.rank == "Head of Personnel"}} - - {{else}} - - {{/if}} - {{/for}} - {{/if}} - {{if data.manifest.misc}} - - {{for data.manifest["misc"]}} - - {{/for}} - {{/if}} -
    Command
    {{:value.name}}{{:value.rank}}{{:value.active}}
    {{:value.name}}{{:value.rank}}{{:value.active}}
    Security
    {{:value.name}}{{:value.rank}}{{:value.active}}
    {{:value.name}}{{:value.rank}}{{:value.active}}
    Engineering
    {{:value.name}}{{:value.rank}}{{:value.active}}
    {{:value.name}}{{:value.rank}}{{:value.active}}
    Medical
    {{:value.name}}{{:value.rank}}{{:value.active}}
    {{:value.name}}{{:value.rank}}{{:value.active}}
    Science
    {{:value.name}}{{:value.rank}}{{:value.active}}
    {{:value.name}}{{:value.rank}}{{:value.active}}
    Service
    {{:value.name}}{{:value.rank}}{{:value.active}}
    {{:value.name}}{{:value.rank}}{{:value.active}}
    Supply
    {{:value.name}}{{:value.rank}}{{:value.active}}
    {{:value.name}}{{:value.rank}}{{:value.active}}
    {{:value.name}}{{:value.rank}}{{:value.active}}
    Civilian
    {{:value.name}}{{:value.rank}}{{:value.active}}
    {{:value.name}}{{:value.rank}}{{:value.active}}
    Misc
    {{:value.name}}{{:value.rank}}{{:value.active}}
    -
    - - - {{else data.mode == 3}} -

    Atmospheric Scan

    -
    -
    - {{if data.aircontents.reading == 1}} -
    - Pressure: -
    -
    - {{:helper.string('{1} kPa', data.aircontents.pressure < 80 || data.aircontents.pressure > 120 ? 'bad' : data.aircontents.pressure < 95 || data.aircontents.pressure > 110 ? 'average' : 'good' , data.aircontents.pressure)}} -
    -
    - Temperature: -
    -
    - {{:helper.string('{1} °C', data.aircontents.temp < 5 || data.aircontents.temp > 35 ? 'bad' : data.aircontents.temp < 15 || data.aircontents.temp > 25 ? 'average' : 'good' , data.aircontents.temp)}} -
    -
    -
    - Oxygen: -
    -
    - {{:helper.string('{1}%', data.aircontents.oxygen < 17 ? 'bad' : data.aircontents.oxygen < 19 ? 'average' : 'good' , data.aircontents.oxygen)}} -
    -
    - Nitrogen: -
    -
    - {{:helper.string('{1}%', data.aircontents.nitrogen > 82 ? 'bad' : data.aircontents.nitrogen > 80 ? 'average' : 'good' , data.aircontents.nitrogen)}} -
    -
    - Carbon Dioxide: -
    -
    - {{:helper.string('{1}%', data.aircontents.carbon_dioxide > 5 ? 'bad' : 'good' , data.aircontents.carbon_dioxide)}} -
    -
    - Plasma: -
    -
    - {{:helper.string('{1}%', data.aircontents.plasma > 0 ? 'bad' : 'good' , data.aircontents.plasma)}} - -
    - {{if data.aircontents.other > 0}} -
    - Unknown: -
    -
    - {{:data.aircontents.other}}% -
    - {{/if}} - {{else}} -
    - Unable to get air reading -
    - {{/if}} -
    -
    - - - {{else data.mode == 40}} -

    Remote Signaling System

    -
    -
    - Frequency: -
    -
    - {{:data.records.signal_freq}} -
    -   - {{:helper.link('-1', null, {'cartmenu' : "1", 'choice' : "Signal Frequency", 'sfreq' : "-10"}, null, null)}}  - {{:helper.link('-.2', null, {'cartmenu' : "1", 'choice' : "Signal Frequency", 'sfreq' : "-2"}, null, null)}}  - - {{:helper.link('+.2', null, {'cartmenu' : "1", 'choice' : "Signal Frequency", 'sfreq' : "2"}, null, null)}}  - {{:helper.link('+1', null, {'cartmenu' : "1", 'choice' : "Signal Frequency", 'sfreq' : "10"}, null, null)}} -
    -
    -
    -
    -
    -
    - Code: -
    -
    - - {{:data.records.signal_code}}
    -
    - {{:helper.link('-5', null, {'cartmenu' : "1", 'choice' : "Signal Code", 'scode' : "-5"}, null, null)}} - {{:helper.link('-1', null, {'cartmenu' : "1", 'choice' : "Signal Code", 'scode' : "-1"}, null, null)}} - {{:helper.link('+1', null, {'cartmenu' : "1", 'choice' : "Signal Code", 'scode' : "1"}, null, null)}} - {{:helper.link('+5', null, {'cartmenu' : "1", 'choice' : "Signal Code", 'scode' : "5"}, null, null)}} -
    -
    -
    - {{:helper.link('Send Signal', 'exclamation-circle', {'cartmenu' : "1", 'choice' : "Send Signal"}, null, null)}} -
    - - - {{else data.mode == 42}} -

    Station Status Displays Interlink

    -
    -
    - Code: -
    -
    - {{:helper.link('Clear', 'trash', {'cartmenu' : "1", 'choice' : "Status", 'statdisp' : "blank"}, null, null)}} - {{:helper.link('Shuttle ETA', 'gear', {'cartmenu' : "1", 'choice' : "Status",'statdisp' : "shuttle"}, null, null)}} - {{:helper.link('Message', 'gear', {'cartmenu' : "1", 'choice' : "Status",'statdisp' : "message"}, null, null)}} -
    -
    -
    -
    -
    - Message line 1 -
    -
    - {{:helper.link(data.records.message1 + ' (set)', 'pencil', {'cartmenu' : "1", 'choice' : "Status",'statdisp' : "setmsg1"}, null, null)}} -
    -
    -
    -
    - Message line 2 -
    -
    - {{:helper.link(data.records.message2 + ' (set)', 'pencil', {'cartmenu' : "1", 'choice' : "Status",'statdisp' : "setmsg2"}, null, null)}} -
    -
    - -
    -
    -
    - ALERT!: -
    -
    - {{:helper.link('None', 'bell', {'cartmenu' : "1", 'choice' : "Status",'statdisp' : "alert", 'exclamation-triangle' : "default"}, null, null)}} - {{:helper.link('Red Alert', 'bell', {'cartmenu' : "1", 'choice' : "Status",'statdisp' : "alert", 'exclamation-triangle' : "redalert"}, null, null)}} - {{:helper.link('Lockdown', 'exclamation-circle', {'cartmenu' : "1", 'choice' : "Status",'statdisp' : "alert", 'exclamation-triangle' : "lockdown"}, null, null)}} - {{:helper.link('Biohazard', 'exclamation-circle', {'cartmenu' : "1", 'choice' : "Status",'statdisp' : "alert", 'exclamation-triangle' : "biohazard"}, null, null)}} -
    -
    - - - {{else data.mode == 43}} -

    Station Power Monitors

    -
    - Select a power monitor: -
    - {{for data.records.powermonitors}} -
    - {{:helper.link(value.Name, 'exclamation-circle', {'cartmenu' : "1", 'choice' : "Power Select",'target' : value.ref}, null, null)}} -
    - {{/for}} - - - {{else data.mode == 433}} -

    Powernet Status

    - {{if data.records.powerconnected == 1}} -
    -
    - Total Power: -
    -
    - {{:data.records.poweravail}} W -
    -
    -
    -
    - Total Load: -
    -
    - {{:data.records.powerload}} W -
    -
    -
    -
    - Total Demand: -
    -
    - {{:data.records.powerdemand}} W -
    -
    -
    - - - {{for data.records.apcs}} - - {{:helper.string('', value.Equipment == "On" || value.Equipment == "AOn" ? '#4f7529' : '#8f1414', value.Equipment)}} - {{:helper.string('', value.Lights == "On" || value.Lights == "AOn" ? '#4f7529' : '#8f1414', value.Lights)}} - {{:helper.string('', value.Environment == "On" || value.Environment == "AOn" ? '#4f7529' : '#8f1414', value.Environment)}} - {{:helper.string('', value.CellStatus == "F" ? '#4f7529' : value.CellStatus == "C" ? '#cd6500' : '#8f1414', value.CellStatus == "M" ? 'No Cell' : value.CellPct + '%', value.CellStatus == "M" ? '' : ' (' + value.CellStatus + ')')}} - - - {{/for}} -
    AreaEquip.LightingEnviron.CellLoad
    {{:value.Name}}{1}{1}{1}{1}{2}{{:value.Load}}W
    -
    - {{else}} - Power monitor not connected to net. - {{/if}} - - - - {{else data.mode == 44}} -

    Medical Record List

    -
    - Select A record -
    -
    - {{for data.records.medical_records}} -
    - {{:helper.link(value.Name, 'gear', {'cartmenu' : "1", 'choice' : "Medical Records",'target' : value.ref}, null, null)}} -
    - {{/for}} - - - {{else data.mode == 441}} -

    Medical Record

    -
    -
    -
    - {{if data.records.general_exists == 1}} - Name: {{:data.records.general.name}}
    - Sex: {{:data.records.general.sex}}
    - Species: {{:data.records.general.species}}
    - Age: {{:data.records.general.age}}
    - Rank: {{:data.records.general.rank}}
    - Fingerprint: {{:data.records.general.fingerprint}}
    - Physical Status: {{:data.records.general.p_stat}}
    - Mental Status: {{:data.records.general.m_stat}}

    - {{else}} - - General Record Lost!

    -
    - {{/if}} - {{if data.records.medical_exists == 1}} - Medical Data:
    - Blood Type: {{:data.records.medical.b_type}}

    - Minor Disabilities: {{:data.records.medical.mi_dis}}
    - Details: {{:data.records.medical.mi_dis_d}}

    - Major Disabilities: {{:data.records.medical.ma_dis}}
    - Details: {{:data.records.medical.ma_dis_d}}

    - Allergies: {{:data.records.medical.alg}}
    - Details: {{:data.records.medical.alg_d}}

    - Current Disease: {{:data.records.medical.cdi}}
    - Details: {{:data.records.medical.alg_d}}

    - Important Notes: {{:data.records.medical.notes}} - {{else}} - - Medical Record Lost! -
    -
    -
    - {{/if}} -
    -
    -
    - - - {{else data.mode == 45}} -

    Security Record List

    -
    - Select A record -
    -
    - {{for data.records.security_records}} -
    - {{:helper.link(value.Name, 'gear', {'cartmenu' : "1", 'choice' : "Security Records",'target' : value.ref}, null, null)}} -
    - {{/for}} - - - {{else data.mode == 451}} -

    Security Record

    -
    -
    -
    - {{if data.records.general_exists == 1}} - Name: {{:data.records.general.name}}
    - Sex: {{:data.records.general.sex}}
    - Species: {{:data.records.general.species}}
    - Age: {{:data.records.general.age}}
    - Rank: {{:data.records.general.rank}}
    - Fingerprint: {{:data.records.general.fingerprint}}
    - Physical Status: {{:data.records.general.p_stat}}
    - Mental Status: {{:data.records.general.m_stat}}

    - {{else}} - - General Record Lost!

    -
    - {{/if}} - {{if data.records.security_exists == 1}} - Security Data:
    - Criminal Status: {{:data.records.security.criminal}}

    - Minor Crimes: {{:data.records.security.mi_crim}}
    - Details: {{:data.records.security.mi_crim_d}}

    - Major Crimes: {{:data.records.security.ma_crim}}
    - Details: {{:data.records.security.ma_crim_d}}

    - Important Notes: {{:data.records.security.notes}} - {{else}} - - Security Record Lost!

    -
    - {{/if}} -
    -
    -
    - - - {{else data.mode == 46}} -

    Security Bot Control

    - {{if data.records.beepsky.active == null || data.records.beepsky.active == 0}} - {{if data.records.beepsky.count == 0}} -

    No bots found.

    - {{else}} -
    - Select A Bot. -
    -
    - {{for data.records.beepsky.bots}} -
    - {{:helper.link(value.Name, 'gear', {'radiomenu' : "1", 'op' : "control",'bot' : value.ref}, null, null)}} (Location: {{:value.Location}}) -
    - {{/for}} - {{/if}} -
    - {{:helper.link('Scan for Bots','gear', {'radiomenu' : "1", 'op' : "scanbots"}, null, null)}} - {{else}} -

    {{:data.records.beepsky.active}}

    -

    - {{if data.records.beepsky.botstatus.mode == -1}} -

    Waiting for response...

    - {{else}} -

    Status:

    -
    -
    -
    - Location: -
    -
    - {{:data.records.beepsky.botstatus.loca}} -
    -
    -
    -
    - Mode: -
    -
    - - {{if data.records.beepsky.botstatus.mode ==0}} - Ready - {{else data.records.beepsky.botstatus.mode == 1}} - Apprehending target - {{else data.records.beepsky.botstatus.mode ==2 || data.records.beepsky.botstatus.mode == 3}} - Arresting target - {{else data.records.beepsky.botstatus.mode ==4}} - Starting patrol - {{else data.records.beepsky.botstatus.mode ==5}} - On Patrol - {{else data.records.beepsky.botstatus.mode ==6}} - Responding to summons - {{/if}} - -
    -
    -
    - {{:helper.link('Stop Patrol', 'gear', {'radiomenu' : "1", 'op' : "stop"}, null, null)}} - {{:helper.link('Start Patrol', 'gear', {'radiomenu' : "1", 'op' : "go"}, null, null)}} - {{:helper.link('Summon Bot', 'gear', {'radiomenu' : "1", 'op' : "summon"}, null, null)}} -
    - {{/if}} - {{:helper.link('Return to Bot list', 'gear', {'radiomenu' : "1", 'op' : "botlist"}, null, null)}} - {{/if}} - - - {{else data.mode == 47}} -

    Supply Record Interlink

    -
    -
    - Location: -
    -
    - - {{if data.records.supply.shuttle_moving}} - Moving to {{:data.records.supply.shuttle_loc}} - {{else}} - Shuttle at {{:data.records.supply.shuttle_loc}} - {{/if}} -
    - {{:data.records.supply.shuttle_time}} -
    -
    -
    -
    -
    -
    - Current Approved Orders
    - {{if data.records.supply.approved_count == 0}} - No current approved orders

    - {{else}} - {{for data.records.supply.approved}} - #{{:value.Number}} - {{:value.Name}} approved by {{:value.OrderedBy}}
    {{if value.Comment != ""}} {{:value.Comment}}
    {{/if}}
    - {{/for}} - {{/if}} -

    - Current Requested Orders
    - {{if data.records.supply.requests_count == 0}} - No current requested orders

    - {{else}} - {{for data.records.supply.requests}} - #{{:value.Number}} - {{:value.Name}} requested by {{:value.OrderedBy}}
    {{if value.Comment != ""}} {{:value.Comment}}
    {{/if}}
    - {{/for}} - {{/if}} -
    -
    -
    - - - {{else data.mode == 48}} -

    Mule Control

    - {{if data.records.mulebot.active == null || data.records.mulebot.active == 0}} - {{if data.records.mulebot.count == 0}} -

    No bots found.

    - {{else}} -

    Mule List

    -
    - Select A Mulebot -
    -
    - {{for data.records.mulebot.bots}} -
    - {{:helper.link(value.Name, 'gear', {'radiomenu' : "1", 'op' : "control",'bot' : value.ref}, null, null)}} (Location: {{:value.Location}}) -
    - {{/for}} - {{/if}} -
    - {{:helper.link('Scan for Bots','gear', {'radiomenu' : "1", 'op' : "scanbots"}, null, null)}} - {{else}} - {{if data.records.mulebot.botstatus.mode == -1}} -

    Waiting for response...

    - {{else}} -

    Status:

    -
    -
    -
    - Location: -
    -
    - {{:data.records.mulebot.botstatus.loca}} -
    -
    -
    -
    - Mode: -
    -
    - - {{if data.records.mulebot.botstatus.mode ==0}} - Ready - {{else data.records.mulebot.botstatus.mode == 1}} - Loading/Unloading - {{else data.records.mulebot.botstatus.mode ==2}} - Navigating to Delivery Location - {{else data.records.mulebot.botstatus.mode == 3}} - Navigating to Home - {{else data.records.mulebot.botstatus.mode ==4}} - Waiting for Clear Path - {{else data.records.mulebot.botstatus.mode ==5 || data.records.mulebot.botstatus.mode == 6}} - Calculating navigation Path - {{else data.records.mulebot.botstatus.mode ==7}} - Unable to locate destination - {{/if}} - -
    -
    -
    -
    - Current Load: -
    -
    - - {{:helper.link(data.records.mulebot.botstatus.load == null ? 'None (Unload)' : data.records.mulebot.botstatus.load + ' (Unload)', 'gear', {'radiomenu' : "1", 'op' : "unload"},data.records.mulebot.botstatus.load == null ? 'disabled' : null, null)}} - -
    -
    -
    -
    - Power: -
    -
    - - {{:data.records.mulebot.botstatus.powr}}% - -
    -
    -
    -
    - Destination: -
    -
    - {{:helper.link(data.records.mulebot.botstatus.dest == null || data.records.mulebot.botstatus.dest == "" ? 'None (Set)': data.records.mulebot.botstatus.dest+ ' (Set)', 'gear', {'radiomenu' : "1", 'op' : "setdest"}, null, null)}} -
    -
    -
    -
    - Home: -
    -
    - {{if data.records.mulebot.botstatus.home == null}} None {{else}} {{:data.records.mulebot.botstatus.home}} {{/if}} -
    -
    -
    -
    - Auto Return: -
    -
    - {{:helper.link(data.records.mulebot.botstatus.retn == 1 ? 'ON' : 'OFF', 'gear', {'radiomenu' : "1", 'op' : data.records.mulebot.botstatus.retn==1 ? "retoff" : "reton"}, null, null)}} -
    -
    -
    -
    - Auto Pickup: -
    -
    - {{:helper.link(data.records.mulebot.botstatus.pick==1? 'ON' : 'OFF', 'gear', {'radiomenu' : "1", 'op' : data.records.mulebot.botstatus.pick==1 ? "pickoff" : "pickon"}, null, null)}} -
    -
    -
    -
    - Functions: -
    -
    - {{:helper.link('Stop', 'gear', {'radiomenu' : "1", 'op' : "stop"}, null, null)}} - {{:helper.link('Proceed', 'gear', {'radiomenu' : "1", 'op' : "go"}, null, null)}} - {{:helper.link('Return Home', 'gear', {'radiomenu' : "1", 'op' : "home"}, null, null)}} -
    -
    -

    - {{:helper.link('Return to Bot list', 'gear', {'radiomenu' : "1", 'op' : "botlist"}, null, null)}} - {{/if}} - {{/if}} - - - {{else data.mode == 49}} -

    Janatorial Supplies Locator

    -
    - Current Location: - {{if data.records.janitor.user_loc.x == 0}} - Unknown - {{else}} - {{:data.records.janitor.user_loc.x}} / {{:data.records.janitor.user_loc.y}} - {{/if}} -
    -
    - {{for data.records.janitor.mops}} - {{if value.x==0}} - Unable to locate Mop - {{else}} - Mop Location: - ({{:value.x}} / {{:value.y}}) - {{:value.dir}} - Status: {{:value.status}}
    - {{/if}} - {{/for}} -
    -
    - {{for data.records.janitor.buckets}} - {{if value.x==0}} - Unable to locate Water Buckets - {{else}} - Water Buckets Location: - ({{:value.x}} / {{:value.y}}) - {{:value.dir}} - Water Level: {{:value.status}}
    - {{/if}} - {{/for}} -
    -
    - {{for data.records.janitor.cleanbots}} - {{if value.x==0}} - Unable to locate Clean Bots - {{else}} - Clean Bots Location: - ({{:value.x}} / {{:value.y}}) - {{:value.dir}} - Status: {{:value.status}}
    - {{/if}} - {{/for}} -
    -
    - {{for data.records.janitor.carts}} - {{if value.x==0}} - Unable to locate Janitorial Cart - {{else}} - Janitorial cart Location: - ({{:value.x}} / {{:value.y}}) - {{:value.dir}} - Status: {{:value.status}}
    - {{/if}} - {{/for}} -
    - {{/if}} {{else}}







    No Owner information found, please swipe ID
    -{{/if}} - +{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_atmos_scan.tmpl b/nano/templates/pda_atmos_scan.tmpl new file mode 100644 index 00000000000..80fa3838995 --- /dev/null +++ b/nano/templates/pda_atmos_scan.tmpl @@ -0,0 +1,60 @@ + +
    +
    + {{if data.aircontents.reading == 1}} +
    + Pressure: +
    +
    + {{:helper.string('{1} kPa', data.aircontents.pressure < 80 || data.aircontents.pressure > 120 ? 'bad' : data.aircontents.pressure < 95 || data.aircontents.pressure > 110 ? 'average' : 'good' , data.aircontents.pressure)}} +
    +
    + Temperature: +
    +
    + {{:helper.string('{1} °C', data.aircontents.temp < 5 || data.aircontents.temp > 35 ? 'bad' : data.aircontents.temp < 15 || data.aircontents.temp > 25 ? 'average' : 'good' , data.aircontents.temp)}} +
    +
    +
    + Oxygen: +
    +
    + {{:helper.string('{1}%', data.aircontents.oxygen < 17 ? 'bad' : data.aircontents.oxygen < 19 ? 'average' : 'good' , data.aircontents.oxygen)}} +
    +
    + Nitrogen: +
    +
    + {{:helper.string('{1}%', data.aircontents.nitrogen > 82 ? 'bad' : data.aircontents.nitrogen > 80 ? 'average' : 'good' , data.aircontents.nitrogen)}} +
    +
    + Carbon Dioxide: +
    +
    + {{:helper.string('{1}%', data.aircontents.carbon_dioxide > 5 ? 'bad' : 'good' , data.aircontents.carbon_dioxide)}} +
    +
    + Plasma: +
    +
    + {{:helper.string('{1}%', data.aircontents.plasma > 0 ? 'bad' : 'good' , data.aircontents.plasma)}} + +
    + {{if data.aircontents.other > 0}} +
    + Unknown: +
    +
    + {{:data.aircontents.other}}% +
    + {{/if}} + {{else}} +
    + Unable to get air reading +
    + {{/if}} +
    +
    \ No newline at end of file diff --git a/nano/templates/pda_janitor.tmpl b/nano/templates/pda_janitor.tmpl new file mode 100644 index 00000000000..a2fd282ad3f --- /dev/null +++ b/nano/templates/pda_janitor.tmpl @@ -0,0 +1,50 @@ +
    +
    + Current Location: + {{if data.janitor.user_loc.x == 0}} + Unknown + {{else}} + {{:data.janitor.user_loc.x}} / {{:data.janitor.user_loc.y}} + {{/if}} +
    +
    + {{for data.janitor.mops}} + {{if value.x==0}} + Unable to locate Mop + {{else}} + Mop Location: + ({{:value.x}} / {{:value.y}}) - {{:value.dir}} - Status: {{:value.status}}
    + {{/if}} + {{/for}} +
    +
    + {{for data.janitor.buckets}} + {{if value.x==0}} + Unable to locate Water Buckets + {{else}} + Water Buckets Location: + ({{:value.x}} / {{:value.y}}) - {{:value.dir}} - Water Level: {{:value.status}}
    + {{/if}} + {{/for}} +
    +
    + {{for data.janitor.cleanbots}} + {{if value.x==0}} + Unable to locate Clean Bots + {{else}} + Clean Bots Location: + ({{:value.x}} / {{:value.y}}) - {{:value.dir}} - Status: {{:value.status}}
    + {{/if}} + {{/for}} +
    +
    + {{for data.janitor.carts}} + {{if value.x==0}} + Unable to locate Janitorial Cart + {{else}} + Janitorial cart Location: + ({{:value.x}} / {{:value.y}}) - {{:value.dir}} - Status: {{:value.status}}
    + {{/if}} + {{/for}} +
    +
    \ No newline at end of file diff --git a/nano/templates/pda_main_menu.tmpl b/nano/templates/pda_main_menu.tmpl new file mode 100644 index 00000000000..680e4a8fa75 --- /dev/null +++ b/nano/templates/pda_main_menu.tmpl @@ -0,0 +1,48 @@ + +
    +
    + Owner: +
    +
    + {{:data.owner}}, {{:data.ownjob}} +
    +
    +
    +
    + ID: +
    +
    + {{:helper.link('Update PDA Info', 'refresh', {'choice' : "UpdateInfo"}, data.idInserted ? null : 'disabled', 'pdalink fixedLeftWide')}} +
    +
    + +
    +

    Functions

    +
    +{{for data.categories : cat : i}} + +{{/for}} + +{{if data.pai}} +
    +
    + PAI Utilities: +
    +
    + {{:helper.link('Configuration', 'gear', {'choice' : "pai", 'option' : "1"}, null, 'pdalink fixedLeft')}} + {{:helper.link('Eject pAI', 'eject', {'choice' : "pai", 'option' : "2"}, null, 'pdalink fixedLeft')}} +
    +
    +{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_manifest.tmpl b/nano/templates/pda_manifest.tmpl new file mode 100644 index 00000000000..ef9e91a088f --- /dev/null +++ b/nano/templates/pda_manifest.tmpl @@ -0,0 +1,96 @@ + +
    +
    + {{if data.manifest.heads}} + + {{for data.manifest["heads"]}} + {{if value.rank == "Captain"}} + + {{else}} + + {{/if}} + {{/for}} + {{/if}} + {{if data.manifest.sec}} + + {{for data.manifest["sec"]}} + {{if value.rank == "Head of Security"}} + + {{else}} + + {{/if}} + {{/for}} + {{/if}} + {{if data.manifest.eng}} + + {{for data.manifest["eng"]}} + {{if value.rank == "Chief Engineer"}} + + {{else}} + + {{/if}} + {{/for}} + {{/if}} + {{if data.manifest.med}} + + {{for data.manifest["med"]}} + {{if value.rank == "Chief Medical Officer"}} + + {{else}} + + {{/if}} + {{/for}} + {{/if}} + {{if data.manifest.sci}} + + {{for data.manifest["sci"]}} + {{if value.rank == "Research Director"}} + + {{else}} + + {{/if}} + {{/for}} + {{/if}} + {{if data.manifest.ser}} + + {{for data.manifest["ser"]}} + {{if value.rank == "Head of Personnel"}} + + {{else}} + + {{/if}} + {{/for}} + {{/if}} + {{if data.manifest.sup}} + + {{for data.manifest["sup"]}} + {{if value.rank == "Head of Personnel"}} + + {{else value.rank == "Quartermaster"}} + + {{else}} + + {{/if}} + {{/for}} + {{/if}} + {{if data.manifest.civ}} + + {{for data.manifest["civ"]}} + {{if value.rank == "Head of Personnel"}} + + {{else}} + + {{/if}} + {{/for}} + {{/if}} + {{if data.manifest.misc}} + + {{for data.manifest["misc"]}} + + {{/for}} + {{/if}} +
    Command
    {{:value.name}}{{:value.rank}}{{:value.active}}
    {{:value.name}}{{:value.rank}}{{:value.active}}
    Security
    {{:value.name}}{{:value.rank}}{{:value.active}}
    {{:value.name}}{{:value.rank}}{{:value.active}}
    Engineering
    {{:value.name}}{{:value.rank}}{{:value.active}}
    {{:value.name}}{{:value.rank}}{{:value.active}}
    Medical
    {{:value.name}}{{:value.rank}}{{:value.active}}
    {{:value.name}}{{:value.rank}}{{:value.active}}
    Science
    {{:value.name}}{{:value.rank}}{{:value.active}}
    {{:value.name}}{{:value.rank}}{{:value.active}}
    Service
    {{:value.name}}{{:value.rank}}{{:value.active}}
    {{:value.name}}{{:value.rank}}{{:value.active}}
    Supply
    {{:value.name}}{{:value.rank}}{{:value.active}}
    {{:value.name}}{{:value.rank}}{{:value.active}}
    {{:value.name}}{{:value.rank}}{{:value.active}}
    Civilian
    {{:value.name}}{{:value.rank}}{{:value.active}}
    {{:value.name}}{{:value.rank}}{{:value.active}}
    Misc
    {{:value.name}}{{:value.rank}}{{:value.active}}
    +
    \ No newline at end of file diff --git a/nano/templates/pda_medical.tmpl b/nano/templates/pda_medical.tmpl new file mode 100644 index 00000000000..777fb91f4b8 --- /dev/null +++ b/nano/templates/pda_medical.tmpl @@ -0,0 +1,54 @@ +{{if !data.records}} +
    +
    Select a record:
    +
    + {{for data.recordsList}} +
    + {{:helper.link(value.Name, 'user', {'choice' : "Records", 'target' : value.ref}, null, 'pdalink fixedLeftWidest')}} +
    + {{empty}} +
    + No records found. +
    + {{/for}} +{{else}} +
    +
    +
    + {{if data.records.general}} + Name: {{:data.records.general.name}}
    + Sex: {{:data.records.general.sex}}
    + Species: {{:data.records.general.species}}
    + Age: {{:data.records.general.age}}
    + Rank: {{:data.records.general.rank}}
    + Fingerprint: {{:data.records.general.fingerprint}}
    + Physical Status: {{:data.records.general.p_stat}}
    + Mental Status: {{:data.records.general.m_stat}}

    + {{else}} + + General Record Lost!

    +
    + {{/if}} + {{if data.records.medical}} +
    +
    Medical Data:
    +
    + Blood Type: {{:data.records.medical.b_type}}

    + Minor Disabilities: {{:data.records.medical.mi_dis}}
    + Details: {{:data.records.medical.mi_dis_d}}

    + Major Disabilities: {{:data.records.medical.ma_dis}}
    + Details: {{:data.records.medical.ma_dis_d}}

    + Allergies: {{:data.records.medical.alg}}
    + Details: {{:data.records.medical.alg_d}}

    + Current Disease: {{:data.records.medical.cdi}}
    + Details: {{:data.records.medical.alg_d}}

    + Important Notes: {{:data.records.medical.notes}} + {{else}} + + Medical Record Lost! + + {{/if}} +
    +
    +
    +{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_messenger.tmpl b/nano/templates/pda_messenger.tmpl new file mode 100644 index 00000000000..633ae7d4691 --- /dev/null +++ b/nano/templates/pda_messenger.tmpl @@ -0,0 +1,81 @@ + +{{if data.active_conversation}} +
    +
    + Messenger Functions: +
    +
    + {{:helper.link('Delete Conversation', 'trash', {'choice' : "Clear", 'option' : "Convo"}, null, 'pdalink fixedLeftWide')}} +
    +
    +
    +
    +

    Conversation with: {{:data.convo_name}} ({{:data.convo_job}})

    +
    +
    +
    + {{for data.messages}} + {{if data.active_conversation == value.target}} + {{if value.sent==0}} + Them: {{:value.message}}
    + {{else}} + You: {{:value.message}}
    + {{/if}} + {{/if}} + {{/for}} +
    +
    +
    + {{:helper.link('Reply', 'comment', {'choice' : "Message", 'target': data.active_conversation}, null, 'pdalink fixedLeft')}} +{{else}} +
    +
    + Messenger Functions: +
    +
    + {{:helper.link(data.silent==1 ? 'Ringer: Off' : 'Ringer: On', data.silent==1 ? 'volume-off' : 'volume-up', {'choice' : "Toggle Ringer"}, null, 'pdalink fixedLeftWide')}} + {{:helper.link(data.toff==1 ? 'Messenger: Off' : 'Messenger: On',data.toff==1 ? 'close':'check', {'choice' : "Toggle Messenger"}, null, 'pdalink fixedLeftWide')}} + {{:helper.link('Set Ringtone', 'comment', {'choice' : "Ringtone"}, null, 'pdalink fixedLeftWide')}} + {{:helper.link('Delete all Conversations', 'trash', {'choice' : "Clear", 'option' : "All"}, null, 'pdalink fixedLeftWider')}} +
    +
    + {{if data.toff == 0}} +
    + {{if data.charges}} +
    + {{:data.charges}} charges left. +

    +
    + {{/if}} + + {{if data.pda_count == 0}} + No other PDAS located + {{else}} +

    Current Conversations

    + {{for data.convopdas}} +
    + {{:helper.link(value.Name, 'arrow-circle-down', {'choice' : "Select Conversation", 'convo' : value.Reference } , null, 'pdalink')}} + {{if data.charges}} + {{for data.plugins : plugin : i}} + {{:helper.link(plugin.name, plugin.icon, {'choice' : "Messenger Plugin", 'plugin' : plugin.ref, 'target' : value.Reference}, null, 'pdalink fixedLeft')}} + {{/for}} + {{/if}} +
    + {{/for}} +

    Other PDAs

    + {{for data.pdas}} +
    + {{:helper.link(value.Name, 'arrow-circle-down', {'choice' : "Message", 'target' : value.Reference}, null, 'pdalink')}} + {{if data.charges}} + {{for data.plugins : plugin : i}} + {{:helper.link(plugin.name, plugin.icon, {'choice' : "Messenger Plugin", 'plugin' : plugin.ref, 'target' : value.Reference}, null, 'pdalink fixedLeft')}} + {{/for}} + {{/if}} +
    + {{/for}} + {{/if}} + {{/if}} +{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_mule.tmpl b/nano/templates/pda_mule.tmpl new file mode 100644 index 00000000000..cf3c5eff6f6 --- /dev/null +++ b/nano/templates/pda_mule.tmpl @@ -0,0 +1,118 @@ +{{if !data.mulebot.active}} + {{if data.mulebot.count == 0}} +

    No bots found.

    + {{else}} +
    + Select a MULE: +
    +
    + {{for data.mulebot.bots}} +
    + {{:helper.link(value.Name, 'gear', {'radiomenu' : "1", 'op' : "control",'bot' : value.ref}, null, 'pdalink fixedLeftWidest')}} (Location: {{:value.Location}}) +
    + {{/for}} + {{/if}} +
    + {{:helper.link('Scan for Bots','rss', {'radiomenu' : "1", 'op' : "scanbots"}, null, 'pdalink fixedLeftWidest')}} +{{else}} +

    {{:data.mulebot.active}}

    + {{if data.mulebot.botstatus.mode == -1}} +

    Waiting for response...

    + {{else}} +

    Status:

    +
    +
    + Location: +
    +
    + {{:data.mulebot.botstatus.loca}} +
    +
    +
    +
    + Mode: +
    +
    + + {{if data.mulebot.botstatus.mode == 0}} + Ready + {{else data.mulebot.botstatus.mode == 1}} + Loading/Unloading + {{else data.mulebot.botstatus.mode == 2}} + Navigating to Delivery Location + {{else data.mulebot.botstatus.mode == 3}} + Navigating to Home + {{else data.mulebot.botstatus.mode == 4}} + Waiting for Clear Path + {{else data.mulebot.botstatus.mode == 5 || data.mulebot.botstatus.mode == 6}} + Calculating navigation Path + {{else data.mulebot.botstatus.mode == 7}} + Unable to locate destination + {{/if}} + +
    +
    +
    +
    + Current Load: +
    +
    + + {{:helper.link(data.mulebot.botstatus.load == null ? 'None (Unload)' : data.mulebot.botstatus.load + ' (Unload)', 'archive', {'radiomenu' : "1", 'op' : "unload"},data.mulebot.botstatus.load == null ? 'disabled' : null, 'pdalink fixedLeftWidest')}} + +
    +
    +
    +
    + Power: +
    +
    + + {{:data.mulebot.botstatus.powr}}% + +
    +
    +
    +
    + Destination: +
    +
    + {{:helper.link(data.mulebot.botstatus.dest == null || data.mulebot.botstatus.dest == "" ? 'None (Set)' : data.mulebot.botstatus.dest + ' (Set)', 'gear', {'radiomenu' : "1", 'op' : "setdest"}, null, 'pdalink fixedLeftWidest')}} +
    +
    +
    +
    + Home: +
    +
    + {{if data.mulebot.botstatus.home == null}} None {{else}} {{:data.mulebot.botstatus.home}} {{/if}} +
    +
    +
    +
    + Auto Return: +
    +
    + {{:helper.link(data.mulebot.botstatus.retn == 1 ? 'ON' : 'OFF', 'gear', {'radiomenu' : "1", 'op' : (data.mulebot.botstatus.retn==1 ? "retoff" : "reton")}, null, 'pdalink fixedLeftWidest')}} +
    +
    +
    +
    + Auto Pickup: +
    +
    + {{:helper.link(data.mulebot.botstatus.pick==1? 'ON' : 'OFF', 'gear', {'radiomenu' : "1", 'op' : (data.mulebot.botstatus.pick==1 ? "pickoff" : "pickon")}, null, 'pdalink fixedLeftWidest')}} +
    +
    +
    +
    + Functions: +
    +
    + {{:helper.link('Stop', 'gear', {'radiomenu' : "1", 'op' : "stop"}, null, 'pdalink fixedLeft')}} + {{:helper.link('Proceed', 'gear', {'radiomenu' : "1", 'op' : "go"}, null, 'pdalink fixedLeft')}} + {{:helper.link('Return Home', 'gear', {'radiomenu' : "1", 'op' : "home"}, null, 'pdalink fixedLeft')}} +
    +
    + {{/if}} +{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_notekeeper.tmpl b/nano/templates/pda_notekeeper.tmpl new file mode 100644 index 00000000000..53db3be6438 --- /dev/null +++ b/nano/templates/pda_notekeeper.tmpl @@ -0,0 +1,21 @@ + +
    +
    + Notes: +
    +
    +
    +
    +
    + {{:data.note}} +
    +
    +
    +
    +
    + {{:helper.link('Edit Notes', 'pencil-square-o', {'choice': "Edit"}, null, 'pdalink')}} +
    +
    \ No newline at end of file diff --git a/nano/templates/pda_power.tmpl b/nano/templates/pda_power.tmpl new file mode 100644 index 00000000000..7ba04188b71 --- /dev/null +++ b/nano/templates/pda_power.tmpl @@ -0,0 +1,49 @@ +{{if !data.records.powerconnected}} +
    +
    Select a power monitor:
    +
    + {{for data.records.powermonitors}} +
    + {{:helper.link(value.Name, 'exclamation-circle', {'choice' : "Power Select", 'target' : value.ref}, null, 'pdalink fixedLeftWidest')}} +
    + {{/for}} +{{else}} +
    +
    + Total Power: +
    +
    + {{:data.records.poweravail}} W +
    +
    +
    +
    + Total Load: +
    +
    + {{:data.records.powerload}} W +
    +
    +
    +
    + Total Demand: +
    +
    + {{:data.records.powerdemand}} W +
    +
    +
    + + + {{for data.records.apcs}} + + {{:helper.string('', value.Equipment == "On" || value.Equipment == "AOn" ? '#4f7529' : '#8f1414', value.Equipment)}} + {{:helper.string('', value.Lights == "On" || value.Lights == "AOn" ? '#4f7529' : '#8f1414', value.Lights)}} + {{:helper.string('', value.Environment == "On" || value.Environment == "AOn" ? '#4f7529' : '#8f1414', value.Environment)}} + {{:helper.string('', value.CellStatus == "F" ? '#4f7529' : value.CellStatus == "C" ? '#cd6500' : '#8f1414', value.CellStatus == "M" ? 'No Cell' : value.CellPct + '%', value.CellStatus == "M" ? '' : ' (' + value.CellStatus + ')')}} + + + {{/for}} +
    AreaEquip.LightingEnviron.CellLoad
    {{:value.Name}}{1}{1}{1}{1}{2}{{:value.Load}}W
    +
    +{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_secbot.tmpl b/nano/templates/pda_secbot.tmpl new file mode 100644 index 00000000000..6ff8c98e147 --- /dev/null +++ b/nano/templates/pda_secbot.tmpl @@ -0,0 +1,59 @@ +{{if !data.beepsky.active}} + {{if data.beepsky.count == 0}} +

    No bots found.

    + {{else}} +
    + Select a bot: +
    +
    + {{for data.beepsky.bots}} +
    + {{:helper.link(value.Name, 'gear', {'radiomenu' : "1", 'op' : "control",'bot' : value.ref}, null, 'pdalink fixedLeftWidest')}} (Location: {{:value.Location}}) +
    + {{/for}} + {{/if}} +
    + {{:helper.link('Scan for Bots','rss', {'radiomenu' : "1", 'op' : "scanbots"}, null, 'pdalink fixedLeftWidest')}} +{{else}} +

    {{:data.beepsky.active}}

    + {{if data.beepsky.botstatus.mode == -1}} +

    Waiting for response...

    + {{else}} +

    Status:

    +
    +
    + Location: +
    +
    + {{:data.beepsky.botstatus.loca}} +
    +
    +
    +
    + Mode: +
    +
    + + {{if data.beepsky.botstatus.mode ==0}} + Ready + {{else data.beepsky.botstatus.mode == 1}} + Apprehending target + {{else data.beepsky.botstatus.mode ==2 || data.beepsky.botstatus.mode == 3}} + Arresting target + {{else data.beepsky.botstatus.mode ==4}} + Starting patrol + {{else data.beepsky.botstatus.mode ==5}} + On Patrol + {{else data.beepsky.botstatus.mode ==6}} + Responding to summons + {{/if}} + +
    +
    +
    + {{:helper.link('Stop Patrol', 'gear', {'radiomenu' : "1", 'op' : "stop"}, null, 'pdalink fixedLeftWide')}} + {{:helper.link('Start Patrol', 'gear', {'radiomenu' : "1", 'op' : "go"}, null, 'pdalink fixedLeftWide')}} + {{:helper.link('Summon Bot', 'gear', {'radiomenu' : "1", 'op' : "summon"}, null, 'pdalink fixedLeftWide')}} +
    + {{/if}} +{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_security.tmpl b/nano/templates/pda_security.tmpl new file mode 100644 index 00000000000..53d40185e05 --- /dev/null +++ b/nano/templates/pda_security.tmpl @@ -0,0 +1,50 @@ +{{if !data.records}} +
    +
    Select a record:
    +
    + {{for data.recordsList}} +
    + {{:helper.link(value.Name, 'user', {'choice' : "Records", 'target' : value.ref}, null, 'pdalink fixedLeftWidest')}} +
    + {{empty}} +
    + No records found. +
    + {{/for}} +{{else}} +
    +
    +
    + {{if data.records.general}} + Name: {{:data.records.general.name}}
    + Sex: {{:data.records.general.sex}}
    + Species: {{:data.records.general.species}}
    + Age: {{:data.records.general.age}}
    + Rank: {{:data.records.general.rank}}
    + Fingerprint: {{:data.records.general.fingerprint}}
    + Physical Status: {{:data.records.general.p_stat}}
    + Mental Status: {{:data.records.general.m_stat}}

    + {{else}} + + General Record Lost!

    +
    + {{/if}} + {{if data.records.security}} +
    +
    Security Data:
    +
    + Criminal Status: {{:data.records.security.criminal}}

    + Minor Crimes: {{:data.records.security.mi_crim}}
    + Details: {{:data.records.security.mi_crim_d}}

    + Major Crimes: {{:data.records.security.ma_crim}}
    + Details: {{:data.records.security.ma_crim_d}}

    + Important Notes: {{:data.records.security.notes}} + {{else}} + + Security Record Lost!

    +
    + {{/if}} +
    +
    +
    +{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_signaller.tmpl b/nano/templates/pda_signaller.tmpl new file mode 100644 index 00000000000..2b5f148b025 --- /dev/null +++ b/nano/templates/pda_signaller.tmpl @@ -0,0 +1,38 @@ + +
    +
    + Frequency: +
    +
    + {{:data.signal_freq}} +
    +   + {{:helper.link('-1', null, {'choice' : "Signal Frequency", 'sfreq' : "-10"}, null, null)}}  + {{:helper.link('-.2', null, {'choice' : "Signal Frequency", 'sfreq' : "-2"}, null, null)}}  + + {{:helper.link('+.2', null, {'choice' : "Signal Frequency", 'sfreq' : "2"}, null, null)}}  + {{:helper.link('+1', null, {'choice' : "Signal Frequency", 'sfreq' : "10"}, null, null)}} +
    +
    +
    +
    +
    +
    + Code: +
    +
    + + {{:data.signal_code}}
    +
    + {{:helper.link('-5', null, {'choice' : "Signal Code", 'scode' : "-5"}, null, null)}} + {{:helper.link('-1', null, {'choice' : "Signal Code", 'scode' : "-1"}, null, null)}} + {{:helper.link('+1', null, {'choice' : "Signal Code", 'scode' : "1"}, null, null)}} + {{:helper.link('+5', null, {'choice' : "Signal Code", 'scode' : "5"}, null, null)}} +
    +
    +
    + {{:helper.link('Send Signal', 'exclamation-circle', {'choice' : "Send Signal"}, null, null)}} +
    \ No newline at end of file diff --git a/nano/templates/pda_status_display.tmpl b/nano/templates/pda_status_display.tmpl new file mode 100644 index 00000000000..8b153ad0ffd --- /dev/null +++ b/nano/templates/pda_status_display.tmpl @@ -0,0 +1,44 @@ + +
    +
    + Code: +
    +
    + {{:helper.link('Clear', 'trash', {'choice' : "Status", 'statdisp' : "blank"}, null, 'pdalink fixedLeftWide')}} + {{:helper.link('Shuttle ETA', 'gear', {'cartmenu' : "1", 'choice' : "Status", 'statdisp' : "shuttle"}, null, 'pdalink fixedLeftWide')}} + {{:helper.link('Message', 'gear', {'choice' : "Status", 'statdisp' : "message"}, null, 'pdalink fixedLeftWide')}} +
    +
    +
    +
    +
    + Message line 1 +
    +
    + {{:helper.link(data.records.message1 + ' (set)', 'pencil', {'choice' : "Status", 'statdisp' : "setmsg1"}, null, 'pdalink fixedLeftWide')}} +
    +
    +
    +
    + Message line 2 +
    +
    + {{:helper.link(data.records.message2 + ' (set)', 'pencil', {'choice' : "Status", 'statdisp' : "setmsg2"}, null, 'pdalink fixedLeftWide')}} +
    +
    + +
    +
    +
    + ALERT!: +
    +
    + {{:helper.link('None', 'bell', {'choice' : "Status", 'statdisp' : "alert", 'alert' : "default"}, null, 'pdalink fixedLeftWide')}} + {{:helper.link('Red Alert', 'bell', {'choice' : "Status", 'statdisp' : "alert", 'alert' : "redalert"}, null, 'pdalink fixedLeftWide')}} + {{:helper.link('Lockdown', 'exclamation-circle', {'choice' : "Status", 'statdisp' : "alert", 'alert' : "lockdown"}, null, 'pdalink fixedLeftWide')}} + {{:helper.link('Biohazard', 'exclamation-circle', {'choice' : "Status", 'statdisp' : "alert", 'alert' : "biohazard"}, null, 'pdalink fixedLeftWide')}} +
    +
    \ No newline at end of file diff --git a/nano/templates/pda_supply.tmpl b/nano/templates/pda_supply.tmpl new file mode 100644 index 00000000000..810fc193769 --- /dev/null +++ b/nano/templates/pda_supply.tmpl @@ -0,0 +1,39 @@ +
    +
    + Location: +
    +
    + + {{if data.supply.shuttle_moving}} + Moving to {{:data.supply.shuttle_loc}} + {{else}} + Shuttle at {{:data.supply.shuttle_loc}} + {{/if}} +
    + {{:data.supply.shuttle_time}} +
    +
    +
    +
    +
    +
    + Current Approved Orders
    + {{if data.supply.approved_count == 0}} + No current approved orders

    + {{else}} + {{for data.supply.approved}} + #{{:value.Number}} - {{:value.Name}} approved by {{:value.OrderedBy}}
    {{if value.Comment != ""}} {{:value.Comment}}
    {{/if}}
    + {{/for}} + {{/if}} +

    + Current Requested Orders
    + {{if data.supply.requests_count == 0}} + No current requested orders

    + {{else}} + {{for data.supply.requests}} + #{{:value.Number}} - {{:value.Name}} requested by {{:value.OrderedBy}}
    {{if value.Comment != ""}} {{:value.Comment}}
    {{/if}}
    + {{/for}} + {{/if}} +
    +
    +
    \ No newline at end of file diff --git a/paradise.dme b/paradise.dme index 7f3586f1537..ca432cad289 100644 --- a/paradise.dme +++ b/paradise.dme @@ -31,6 +31,7 @@ #include "code\__DEFINES\math.dm" #include "code\__DEFINES\misc.dm" #include "code\__DEFINES\mob.dm" +#include "code\__DEFINES\pda.dm" #include "code\__DEFINES\preferences.dm" #include "code\__DEFINES\process_scheduler.dm" #include "code\__DEFINES\qdel.dm" @@ -672,10 +673,6 @@ #include "code\game\objects\items\devices\uplinks.dm" #include "code\game\objects\items\devices\violin.dm" #include "code\game\objects\items\devices\whistle.dm" -#include "code\game\objects\items\devices\PDA\cart.dm" -#include "code\game\objects\items\devices\PDA\chatroom.dm" -#include "code\game\objects\items\devices\PDA\PDA.dm" -#include "code\game\objects\items\devices\PDA\radio.dm" #include "code\game\objects\items\devices\radio\beacon.dm" #include "code\game\objects\items\devices\radio\electropack.dm" #include "code\game\objects\items\devices\radio\encryptionkey.dm" @@ -989,6 +986,8 @@ #include "code\modules\arcade\arcade_base.dm" #include "code\modules\arcade\arcade_prize.dm" #include "code\modules\arcade\claw_game.dm" +#include "code\modules\arcade\prize_counter.dm" +#include "code\modules\arcade\prize_datums.dm" #include "code\modules\assembly\assembly.dm" #include "code\modules\assembly\bomb.dm" #include "code\modules\assembly\health.dm" @@ -1577,6 +1576,18 @@ #include "code\modules\paperwork\photography.dm" #include "code\modules\paperwork\silicon_photography.dm" #include "code\modules\paperwork\stamps.dm" +#include "code\modules\pda\ai.dm" +#include "code\modules\pda\app.dm" +#include "code\modules\pda\cart.dm" +#include "code\modules\pda\cart_apps.dm" +#include "code\modules\pda\chatroom.dm" +#include "code\modules\pda\core_apps.dm" +#include "code\modules\pda\messenger.dm" +#include "code\modules\pda\messenger_plugins.dm" +#include "code\modules\pda\PDA.dm" +#include "code\modules\pda\pdas.dm" +#include "code\modules\pda\radio.dm" +#include "code\modules\pda\utilities.dm" #include "code\modules\pooling\pool.dm" #include "code\modules\power\apc.dm" #include "code\modules\power\cable.dm" diff --git a/sound/machines/synth_no.ogg b/sound/machines/synth_no.ogg new file mode 100644 index 00000000000..f0d2c3bfb0c Binary files /dev/null and b/sound/machines/synth_no.ogg differ diff --git a/sound/machines/synth_yes.ogg b/sound/machines/synth_yes.ogg new file mode 100644 index 00000000000..300cad132ed Binary files /dev/null and b/sound/machines/synth_yes.ogg differ