mirror of
https://github.com/PolarisSS13/Polaris.git
synced 2026-08-23 13:17:03 +01:00
Updates AI branch to Master (#5591)
* Fixes 6 pAI faces PAIs are no longer coded to only recognize 9 emotions. This enables the use of the neutral, silly, nose, smirk, exclamation points, and question mark faces as a pAI. Before, those buttons did nothing. * Fixes the PDA Halogen Scanner's tendency to be number one. * Unfolded pAIs can be picked up Because who doesn't want a robotic cat on their head? Adds in the missing code to allow pAIs to actually be picked up, and held sprites for the newer 4 chassis options. * Adds the Gigaphone, a suped-up Megaphone. * Constant Chip has a sprite * Fireaxe cabinets find their fireaxes in initialize(), rather than new() * Speeds up alcohol * fixed mining cloak not being in loadouts * Admin Supermatter Setup now closes the monitoring room shutters (#5442) * Admin Supermatter Setup now closes the monitoring room shutters * Fixes a copy-paste error * Begins work on lightning. * Fixes #5447 (Deadspy submap not overwriting mapgen) (#5448) * Map fix * fixed deadspy.dmm * Added Squid plushies of varying colours I added a few Squid plushies in different colours, changing the files code/game/objects/items/toys.dm and obj/toy.dmi * Added hat functionality to Squid plushies I added the ability to wear my Squid plushies as hats. They're damn good hats. * Replaces Skrell namegen (#5453) Created a first name list for Skrell, to replace the syllable assembler. Created a surname list for Skrell to replace the syllable assembler. Replaced the Skrell namegen with pre-written namelists, instead of the old syllable assembler. * Mechoid makes mistakes. Fix telepathic gigaphones. * Lets people be colorblind Adds four types of colorblindness to the traits in the setup menu - protanopia, deuteranopia, tritanopia, and monochromacy. Previously, there were ones defined in the code, but not actually usable to players. * Whoops, worded that wrong * Adds beams to the Type var list for View Variables. * Unfuck my Master * Adds beams to the Type var selection in View Variables. * Finishes thunderstorms. * Adds logging. * APC Sprite Change - Port from Virgo recolored slightly to match closer to the old sprite - Addition of directional sprites for the APCs * Refactors supply controller. Supply consoles now run nanoUI * Missing ' * [Excitedly updates changelog] * btw i use arc * Removes supermatters from cave PoIs. * Holomap Port - Port of Holomaps from Virgo * Changing species (via ling or admin button) should no longer ruin your HUD * Converts most istype(thing,tool) procs into an appropriate thing.is_tool() format * Removes empty file, gives the QM a control console again (Was replaced with an ordering console) * Hopefully fixes some tool-conversion things * Makes the Northern Star still compile * Keeps NS up to date * Taj and Unathi should have explorer mask sprites now * Corgi rune now summons the corgi in a flash of harmless lightning * Forces mech construction to work with the is_tool() procs * Various things and floors no longer associate with dirt * MultiZ falling tweaks * Fixes the clusterbang grenade * Added new hairstyles * Added new hairstyles * Fixes spelling of Strike in Lightning Strike admin verb * I don't know how we keep breaking falling * Hallucinations now use the old system again, but with the more modern components. * Ambience Refactor (#5476) * Refactors how ambience is assigned, removes bad ambience, ports good ambience from tg * Apparently that file is still used, not worth the salt to remove it. * Changelog * The speed-related chem effects are no longer a one-or-none affair, oxy causes slowdown * Corrects noted issues * Add some missing sprites for xenoarch excavation. * Become thwarted, thot. * Fixes the Ultra AC2's burstfire bug. * The Major Bill's shuttle is actually contagious now. * penguins are from earth capitalize this, anewbe, i dare you * Mechoid's a butt * Adds new job/department specific teshari clothing to the loadout (#5481) * adding the new department specific teshari outfits * Slightly cleans up hooded suit code (#5471) * FBPs can have brute damage repaired externally again * Windoors fix * Cleans up some largecrate code * Weather refactor. * NanoUI makes me sad. * Drinking more booze gets you drunk faster * Ports the supermatter grenade, supporting code * May or may not make movement seem smoother * Fixes the Sleepy Ring * Partially ports the GLOB system * Fixes the bug(s) that allow meat bodies to have metal brains * ports VOREStation/VOREStation#4165 - i forgot to check if advanced who was a thing here * Optimizes supply UI * Transfer shuttle grammar fixes * Fixes borked E and W fish sprites * Fixes incorrect ETA in crew transfer announcement * Ports descriptors from Bay * Add files via upload * Removes Noble Defines * Mech Mini 'Revamp'. Will need playtesting. (#5480) * Exosuits are now capable of holding more equipment, of specific types. * Tweaks regarding feedback in staffside thread, other concerns. * Tweak to be more consistent. Why did the Odysseus have two universals. Tweak to weapon restriction on Med - > Odyss * Weapons only fit in universal combat slots. * Adds smart magazine, magazine functionality * Adds a new subset of grenades that shoot projectiles * Low alpha now makes HUDs and tooltips not show up on you * Fixes a UI bug with emptying currently-open bags into smartfridges...hopefully. (#5515) * Update smartfridge.dm * actually indicates which line solves the bug * Adds a whole bunch of Exosuit weapons and other miscellaneous parts. * Minifrags now use the small fragments mainly as they should. * Iced beer no longer freezes you to 3 degrees C, which is enough to seriously burn a Skrell. Seriously, that's weird. * Touch stuff in reference to responses. * NanoUI now processes again * Initial Work: Manifest, Newsfeed * Adds newscast viewing, manifest * Cartridge devices * Template progress * Med records, Sec records, Emp records * Cartridge work part 1 * Cartridge work: part 2 * Power monitoring console * Cartridges have persistent, internal data * Code to load element-specific data upon request, instead of serving all relevant data at once * Janitorial Supply Locator * Refactor crew manifest to a separate file * GPS cartridge * Reorganize GPS to proper organization, important comments * Supply cartridge * Status display access * Merc blast door controller * Appeases travis (Round 1) * Appeases travis (Round 2) * Headset sprites are now on the default ear, which is left * Cleave changes, attack code cleanup * Catching is no longer guaranteed, accuracy code is more general * Adds a Neural implant for future implementation. Promethean brains have been updated to fit it. * changelog * Robots can attack things again * Might help with air subsystem lag * Ports the spinny throwing animation from Bay * Cult heal modifier no longer does Shit-Tons of agony. Does mediocre agony on non-cultists. * Defines. * Headset sprite tweaks * Shield Drone no longer auto-fails with Energy Relays. * I'm an idiot. * PoIs can be rotated in increments of 90 degrees * Might fix the server startup error_handler runtime * Cult Girders are back to being proper. * Submaps can now be rotated to any cardinal direction (South is default) * Should fix another runtime with tools * Buffs the Vox * Removes debug code (Yes, I'm an idiot) * Ready for merge * Fixes some bugs tangentially related to Vox code * Ports /vg/ instrument frame work, adds client based sound pref Also shifts sound files which is 98% of the bulk here. * Helmets now show only certain hairstyles * fixes the trailing tag, I think * Scrubbers no longer automatically scrub phoron (#5512) * adds manual changelog * Adds new set of cyborg sprites for medical/science/default/security/combat (#5546) * Refactor cargo trains, they're just normal trains now. Adds the Quad, and re-enables/fixes the Space Bike! * communicator_header.tmpl now correctly includes Body * Adds tails to Unathi rig suit sprites (#5551) * supplycom/control drops the correct circuit * Emags have an effect on cargo consoles * The cybersuit is now a space suit. * Map Bugfixes - Fix for mislabeled c_tag cameras, first deck - Fix for mislabeled c_tag cameras, second deck - Fix for poi crashed containment shuttle mapping issues (terrain generation) - Fixed wrong floor type on skipjack - Fix for scrubbers pipe, central substation - Fix for air supply pipe, chapel - Fixed scrubber pipe, Engineering Drone Fab - Fix for air supply pipe, Prison Wing - Removed redundant supply and scrubber pipe, Security Auxiliary Dock - Fix, Fore Aux Dock airlock pipe. - Fix air supply pipe, library - Fix, scrubber pipe, coffee shop - Pipe fix, Medical maint - Fix, supply pipe medical secondary storage - Removal, redundant supply pipe, cargo maint - Fix, virology scrubbers pipes - Fix Xenobio and Xenoflora missing atmos connection to the main outpost - Fix, missing atmos connections between Main outpost telecoms and main outpost atmos - Fix for missing power wires, HoS Office, Warden Office, Heads of Staff Meeting Room - New, random mouse spawner - New, random mouse spawners added throughout maintenance on the station (maybe too many, maus station 13) - New, 30 sheets of lead added to engineering - Fix, POIs should now be rad protected and characters won’t be affected by the radiation event * Fixes Lead Walls (#5562) A material's ``radiation_resistance`` was never considered for calculating a wall's cached resistance to radiation. This fixes it. There is another issue involving r-walls not being better at stopping radiation than their normal-wall counterparts made of the same material but fixing that involves a lot of number adjusting to avoid the SM engine from getting twice as protective. * Yet Another Circuit Update (#5549) * Circuit updates, adds new components, improves printer, new assemblies. * Finishes powernet circuit. * Adds wearable assemblies. * Finialization before merging with GLOB port. * Finishes circuit update, hopefully. * Forgot to undo map. * Removes debug output. * Readds size traits * Signal pistol can be reloaded (#5566) * Makes Blobs more useful. * Rig and Spacesuit additions - Added the 'military' Rigsuit from Bay. - Added 'pmc' rigsuits - Added exploration and pilot voidsuits along with alternate sprites (alternate sprites done by Naidh) - Addition of suit cyclers for exploration and pilot voidsuits None of these suits are currently accessible in game outside of admin bus. Currently only the pilot voidsuits have other species sprites. Exploration suits are missing sprites for Teshari (Naidh made some for their alternates but I have to add them) and the rig suits are human only. This is to be fixed in the near future, just wanted to get the make workload actually in the game first. * Dermal implant doesn't cover hair * Fixes a couple of tool related oversight/runtimes * Fixes hand and leg cuffs * Update combat.dm * Boot knives fit in boots * Adds tails to Unathi rigsuits (again) * PoI fix * Fixes some more errors, makes it compile, fixes inability for simplemobs to attack windows.
This commit is contained in:
@@ -94,3 +94,8 @@
|
||||
icon_state = "snowwall"
|
||||
plane = MOB_PLANE
|
||||
layer = ABOVE_MOB_LAYER
|
||||
|
||||
/obj/effect/overlay/holographic
|
||||
mouse_opacity = FALSE
|
||||
anchored = TRUE
|
||||
plane = ABOVE_PLANE
|
||||
|
||||
@@ -200,6 +200,9 @@
|
||||
|
||||
/obj/item/attack_hand(mob/living/user as mob)
|
||||
if (!user) return
|
||||
if(anchored)
|
||||
to_chat(user, span("notice", "\The [src] won't budge, you can't pick it up!"))
|
||||
return
|
||||
if (hasorgans(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
var/obj/item/organ/external/temp = H.organs_by_name["r_hand"]
|
||||
|
||||
@@ -655,6 +655,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
|
||||
ui = new(user, src, ui_key, "pda.tmpl", title, 520, 400, state = inventory_state)
|
||||
// add templates for screens in common with communicator.
|
||||
ui.add_template("atmosphericScan", "atmospheric_scan.tmpl")
|
||||
ui.add_template("crewManifest", "crew_manifest.tmpl")
|
||||
// when the ui is first opened this is the data it will use
|
||||
ui.set_initial_data(data)
|
||||
// open the new ui window
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
var/im_list_ui[0] //List of messages.
|
||||
|
||||
var/weather[0]
|
||||
var/injection = null
|
||||
var/modules_ui[0] //Home screen info.
|
||||
|
||||
//First we add other 'local' communicators.
|
||||
@@ -82,12 +81,14 @@
|
||||
)
|
||||
weather[++weather.len] = W
|
||||
|
||||
injection = "<div>Test</div>"
|
||||
// Update manifest
|
||||
data_core.get_manifest_list()
|
||||
|
||||
//Modules for homescreen.
|
||||
for(var/list/R in modules)
|
||||
modules_ui[++modules_ui.len] = R
|
||||
|
||||
data["user"] = "\ref[user]" // For receiving input() via topic, because input(usr,...) wasn't working on cartridges
|
||||
data["owner"] = owner ? owner : "Unset"
|
||||
data["occupation"] = occupation ? occupation : "Swipe ID to set."
|
||||
data["connectionStatus"] = get_connection_to_tcomms()
|
||||
@@ -111,16 +112,29 @@
|
||||
data["weather"] = weather
|
||||
data["aircontents"] = src.analyze_air()
|
||||
data["flashlight"] = fon
|
||||
data["injection"] = injection
|
||||
data["manifest"] = PDA_Manifest
|
||||
data["feeds"] = compile_news()
|
||||
data["latest_news"] = get_recent_news()
|
||||
if(cartridge) // If there's a cartridge, we need to grab the information from it
|
||||
data["cart_devices"] = cartridge.get_device_status()
|
||||
data["cart_templates"] = cartridge.ui_templates
|
||||
for(var/list/L in cartridge.get_data())
|
||||
data[L["field"]] = L["value"]
|
||||
// cartridge.get_data() returns a list of tuples:
|
||||
// The field element is the tag used to access the information by the template
|
||||
// The value element is the actual data, and can take any form necessary for the template
|
||||
|
||||
// update the ui if it exists, returns null if no ui is passed/found
|
||||
ui = GLOB.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, "communicator.tmpl", "Communicator", 475, 700, state = key_state)
|
||||
data["currentTab"] = 1 // Reset the current tab, because we're going to home page
|
||||
ui = new(user, src, ui_key, "communicator_header.tmpl", "Communicator", 475, 700, state = key_state)
|
||||
// add templates for screens in common with communicator.
|
||||
ui.add_template("atmosphericScan", "atmospheric_scan.tmpl")
|
||||
ui.add_template("crewManifest", "crew_manifest.tmpl")
|
||||
ui.add_template("Body", "communicator.tmpl") // Main body
|
||||
// when the ui is first opened this is the data it will use
|
||||
ui.set_initial_data(data)
|
||||
// open the new ui window
|
||||
@@ -168,7 +182,7 @@
|
||||
|
||||
if(href_list["dial"])
|
||||
if(!get_connection_to_tcomms())
|
||||
usr << "<span class='danger'>Error: Cannot connect to Exonet node.</span>"
|
||||
to_chat(usr, "<span class='danger'>Error: Cannot connect to Exonet node.</span>")
|
||||
return
|
||||
var/their_address = href_list["dial"]
|
||||
exonet.send_message(their_address, "voice")
|
||||
@@ -181,7 +195,7 @@
|
||||
|
||||
if(href_list["message"])
|
||||
if(!get_connection_to_tcomms())
|
||||
usr << "<span class='danger'>Error: Cannot connect to Exonet node.</span>"
|
||||
to_chat(usr, "<span class='danger'>Error: Cannot connect to Exonet node.</span>")
|
||||
return
|
||||
var/their_address = href_list["message"]
|
||||
var/text = sanitizeSafe(input(usr,"Enter your message.","Text Message"))
|
||||
@@ -246,9 +260,21 @@
|
||||
note = ""
|
||||
notehtml = note
|
||||
|
||||
if(href_list["switch_template"])
|
||||
var/datum/nanoui/ui = GLOB.nanomanager.get_open_ui(usr, src, "main")
|
||||
if(ui)
|
||||
ui.add_template("Body", href_list["switch_template"])
|
||||
|
||||
if(href_list["Light"])
|
||||
fon = !fon
|
||||
set_light(fon * flum)
|
||||
|
||||
if(href_list["toggle_device"])
|
||||
var/obj/O = cartridge.internal_devices[text2num(href_list["toggle_device"])]
|
||||
cartridge.active_devices ^= list(O) // Exclusive or, will toggle its presence
|
||||
|
||||
if(href_list["cartridge_topic"] && cartridge) // Has to have a cartridge to perform these functions
|
||||
cartridge.Topic(href, href_list)
|
||||
|
||||
GLOB.nanomanager.update_uis(src)
|
||||
add_fingerprint(usr)
|
||||
|
||||
@@ -0,0 +1,952 @@
|
||||
// Communicator peripheral devices
|
||||
// Internal devices that attack() can be relayed to
|
||||
// Additional UI menus for added functionality
|
||||
/obj/item/weapon/commcard
|
||||
name = "generic commcard"
|
||||
desc = "A peripheral plug-in for personal communicators."
|
||||
icon = 'icons/obj/pda.dmi'
|
||||
icon_state = "cart"
|
||||
item_state = "electronic"
|
||||
w_class = ITEMSIZE_TINY
|
||||
|
||||
var/list/internal_devices = list() // Devices that can be toggled on to trigger on attack()
|
||||
var/list/active_devices = list() // Devices that will be triggered on attack()
|
||||
var/list/ui_templates = list() // List of ui templates the commcard can access
|
||||
var/list/internal_data = list() // Data that shouldn't be updated every time nanoUI updates, or needs to persist between updates
|
||||
|
||||
|
||||
/obj/item/weapon/commcard/proc/get_device_status()
|
||||
var/list/L = list()
|
||||
var/i = 1
|
||||
for(var/obj/I in internal_devices)
|
||||
if(I in active_devices)
|
||||
L[++L.len] = list("name" = "\proper[I.name]", "active" = 1, "index" = i++)
|
||||
else
|
||||
L[++L.len] = list("name" = I.name, "active" = 0, "index" = i++)
|
||||
return L
|
||||
|
||||
|
||||
// cartridge.get_data() returns a list of tuples:
|
||||
// The field element is the tag used to access the information by the template
|
||||
// The value element is the actual data, and can take any form necessary for the template
|
||||
/obj/item/weapon/commcard/proc/get_data()
|
||||
return list()
|
||||
|
||||
// Handles cartridge-specific functions
|
||||
// The helper.link() MUST HAVE 'cartridge_topic' passed into the href in order for cartridge functions to be processed.
|
||||
// Doesn't matter what the value of it is for now, it's just a flag to say, "Hey, there's cartridge data to change!"
|
||||
/obj/item/weapon/commcard/Topic(href, href_list)
|
||||
|
||||
// Signalers
|
||||
if(href_list["signaler_target"])
|
||||
|
||||
var/obj/item/device/assembly/signaler/S = locate(href_list["signaler_target"]) // Should locate the correct signaler
|
||||
|
||||
if(!istype(S)) // Ref is no longer valid
|
||||
return
|
||||
|
||||
if(S.loc != src) // No longer within the cartridge
|
||||
return
|
||||
|
||||
switch(href_list["signaler_action"])
|
||||
if("Pulse")
|
||||
S.activate()
|
||||
|
||||
if("Edit")
|
||||
var/mob/user = locate(href_list["user"])
|
||||
if(!istype(user)) // Ref no longer valid
|
||||
return
|
||||
|
||||
var/newVal = input(user, "Input a new [href_list["signaler_value"]].", href_list["signaler_value"], (href_list["signaler_value"] == "Code" ? S.code : S.frequency)) as num|null
|
||||
if(newVal)
|
||||
switch(href_list["signaler_value"])
|
||||
if("Code")
|
||||
S.code = newVal
|
||||
|
||||
if("Frequency")
|
||||
S.frequency = newVal
|
||||
|
||||
// Refresh list of powernet sensors
|
||||
if(href_list["powernet_refresh"])
|
||||
internal_data["grid_sensors"] = find_powernet_sensors()
|
||||
|
||||
// Load apc's on targeted powernet
|
||||
if(href_list["powernet_target"])
|
||||
internal_data["powernet_target"] = href_list["powernet_target"]
|
||||
|
||||
// GPS units
|
||||
if(href_list["gps_target"])
|
||||
var/obj/item/device/gps/G = locate(href_list["gps_target"])
|
||||
|
||||
if(!istype(G)) // Ref is no longer valid
|
||||
return
|
||||
|
||||
if(G.loc != src) // No longer within the cartridge
|
||||
return
|
||||
|
||||
switch(href_list["gps_action"])
|
||||
if("Power")
|
||||
G.tracking = text2num(href_list["value"])
|
||||
|
||||
if("Long_Range")
|
||||
G.local_mode = text2num(href_list["value"])
|
||||
|
||||
if("Hide_Signal")
|
||||
G.hide_signal = text2num(href_list["value"])
|
||||
|
||||
if("Tag")
|
||||
var/mob/user = locate(href_list["user"])
|
||||
if(!istype(user)) // Ref no longer valid
|
||||
return
|
||||
|
||||
var/newTag = input(user, "Please enter desired tag.", G.tag) as text|null
|
||||
|
||||
if(newTag)
|
||||
G.tag = newTag
|
||||
|
||||
if(href_list["active_category"])
|
||||
internal_data["supply_category"] = href_list["active_category"]
|
||||
|
||||
// Supply topic
|
||||
// Copied from /obj/machinery/computer/supplycomp/Topic()
|
||||
// code\game\machinery\computer\supply.dm, line 188
|
||||
// Unfortunately, in order to support complete functionality, the whole thing is necessary
|
||||
if(href_list["pack_ref"])
|
||||
var/datum/supply_pack/S = locate(href_list["pack_ref"])
|
||||
|
||||
// Invalid ref
|
||||
if(!istype(S))
|
||||
return
|
||||
|
||||
// Expand the supply pack's contents
|
||||
if(href_list["expand"])
|
||||
internal_data["supply_pack_expanded"] ^= S
|
||||
|
||||
// Make a request for the pack
|
||||
if(href_list["request"])
|
||||
var/mob/user = locate(href_list["user"])
|
||||
if(!istype(user)) // Invalid ref
|
||||
return
|
||||
|
||||
if(world.time < internal_data["supply_reqtime"])
|
||||
visible_message("<span class='warning'>[src] flashes, \"[internal_data["supply_reqtime"] - world.time] seconds remaining until another requisition form may be printed.\"</span>")
|
||||
return
|
||||
|
||||
var/timeout = world.time + 600
|
||||
var/reason = sanitize(input(user, "Reason:","Why do you require this item?","") as null|text)
|
||||
if(world.time > timeout)
|
||||
to_chat(user, "<span class='warning'>Error. Request timed out.</span>")
|
||||
return
|
||||
if(!reason)
|
||||
return
|
||||
|
||||
supply_controller.create_order(S, user, reason)
|
||||
internal_data["supply_reqtime"] = (world.time + 5) % 1e5
|
||||
|
||||
if(href_list["order_ref"])
|
||||
var/datum/supply_order/O = locate(href_list["order_ref"])
|
||||
|
||||
// Invalid ref
|
||||
if(!istype(O))
|
||||
return
|
||||
|
||||
var/mob/user = locate(href_list["user"])
|
||||
if(!istype(user)) // Invalid ref
|
||||
return
|
||||
|
||||
if(href_list["edit"])
|
||||
var/new_val = sanitize(input(user, href_list["edit"], "Enter the new value for this field:", href_list["default"]) as null|text)
|
||||
if(!new_val)
|
||||
return
|
||||
|
||||
switch(href_list["edit"])
|
||||
if("Supply Pack")
|
||||
O.name = new_val
|
||||
|
||||
if("Cost")
|
||||
var/num = text2num(new_val)
|
||||
if(num)
|
||||
O.cost = num
|
||||
|
||||
if("Index")
|
||||
var/num = text2num(new_val)
|
||||
if(num)
|
||||
O.index = num
|
||||
|
||||
if("Reason")
|
||||
O.comment = new_val
|
||||
|
||||
if("Ordered by")
|
||||
O.ordered_by = new_val
|
||||
|
||||
if("Ordered at")
|
||||
O.ordered_at = new_val
|
||||
|
||||
if("Approved by")
|
||||
O.approved_by = new_val
|
||||
|
||||
if("Approved at")
|
||||
O.approved_at = new_val
|
||||
|
||||
if(href_list["approve"])
|
||||
supply_controller.approve_order(O, user)
|
||||
|
||||
if(href_list["deny"])
|
||||
supply_controller.deny_order(O, user)
|
||||
|
||||
if(href_list["delete"])
|
||||
supply_controller.delete_order(O, user)
|
||||
|
||||
if(href_list["clear_all_requests"])
|
||||
var/mob/user = locate(href_list["user"])
|
||||
if(!istype(user)) // Invalid ref
|
||||
return
|
||||
|
||||
supply_controller.deny_all_pending(user)
|
||||
|
||||
if(href_list["export_ref"])
|
||||
var/datum/exported_crate/E = locate(href_list["export_ref"])
|
||||
|
||||
// Invalid ref
|
||||
if(!istype(E))
|
||||
return
|
||||
|
||||
var/mob/user = locate(href_list["user"])
|
||||
if(!istype(user)) // Invalid ref
|
||||
return
|
||||
|
||||
if(href_list["index"])
|
||||
var/list/L = E.contents[href_list["index"]]
|
||||
|
||||
if(href_list["edit"])
|
||||
var/field = alert(user, "Select which field to edit", , "Name", "Quantity", "Value")
|
||||
|
||||
var/new_val = sanitize(input(user, href_list["edit"], "Enter the new value for this field:", href_list["default"]) as null|text)
|
||||
if(!new_val)
|
||||
return
|
||||
|
||||
switch(field)
|
||||
if("Name")
|
||||
L["object"] = new_val
|
||||
|
||||
if("Quantity")
|
||||
var/num = text2num(new_val)
|
||||
if(num)
|
||||
L["quantity"] = num
|
||||
|
||||
if("Value")
|
||||
var/num = text2num(new_val)
|
||||
if(num)
|
||||
L["value"] = num
|
||||
|
||||
if(href_list["delete"])
|
||||
E.contents.Cut(href_list["index"], href_list["index"] + 1)
|
||||
|
||||
// Else clause means they're editing/deleting the whole export report, rather than a specific item in it
|
||||
else if(href_list["edit"])
|
||||
var/new_val = sanitize(input(user, href_list["edit"], "Enter the new value for this field:", href_list["default"]) as null|text)
|
||||
if(!new_val)
|
||||
return
|
||||
|
||||
switch(href_list["edit"])
|
||||
if("Name")
|
||||
E.name = new_val
|
||||
|
||||
if("Value")
|
||||
var/num = text2num(new_val)
|
||||
if(num)
|
||||
E.value = num
|
||||
|
||||
else if(href_list["delete"])
|
||||
supply_controller.delete_export(E, user)
|
||||
|
||||
else if(href_list["add_item"])
|
||||
supply_controller.add_export_item(E, user)
|
||||
|
||||
if(supply_controller && supply_controller.shuttle)
|
||||
switch(href_list["send_shuttle"])
|
||||
if("send_away")
|
||||
if(supply_controller.shuttle.forbidden_atoms_check())
|
||||
to_chat(usr, "<span class='warning'>For safety reasons the automated supply shuttle cannot transport live organisms, classified nuclear weaponry or homing beacons.</span>")
|
||||
else
|
||||
supply_controller.shuttle.launch(src)
|
||||
to_chat(usr, "<span class='notice'>Initiating launch sequence.</span>")
|
||||
|
||||
if("send_to_station")
|
||||
supply_controller.shuttle.launch(src)
|
||||
to_chat(usr, "<span class='notice'>The supply shuttle has been called and will arrive in approximately [round(supply_controller.movetime/600,1)] minutes.</span>")
|
||||
|
||||
if("cancel_shuttle")
|
||||
supply_controller.shuttle.cancel_launch(src)
|
||||
|
||||
if("force_shuttle")
|
||||
supply_controller.shuttle.force_launch(src)
|
||||
|
||||
// Status display
|
||||
switch(href_list["stat_display"])
|
||||
if("message")
|
||||
post_status("message", internal_data["stat_display_line1"], internal_data["stat_display_line2"])
|
||||
internal_data["stat_display_special"] = "message"
|
||||
if("alert")
|
||||
post_status("alert", href_list["alert"])
|
||||
internal_data["stat_display_special"] = href_list["alert"]
|
||||
if("setmsg")
|
||||
internal_data["stat_display_line[href_list["line"]]"] = reject_bad_text(sanitize(input("Line 1", "Enter Message Text", internal_data["stat_display_line[href_list["line"]]"]) as text|null, 40), 40)
|
||||
else
|
||||
post_status(href_list["stat_display"])
|
||||
internal_data["stat_display_special"] = href_list["stat_display"]
|
||||
|
||||
// Merc shuttle blast door controls
|
||||
switch(href_list["all_blast_doors"])
|
||||
if("open")
|
||||
for(var/obj/machinery/door/blast/B in internal_data["shuttle_doors"])
|
||||
B.open()
|
||||
if("close")
|
||||
for(var/obj/machinery/door/blast/B in internal_data["shuttle_doors"])
|
||||
B.close()
|
||||
|
||||
if(href_list["scan_blast_doors"])
|
||||
internal_data["shuttle_doors"] = find_blast_doors()
|
||||
|
||||
if(href_list["toggle_blast_door"])
|
||||
var/obj/machinery/door/blast/B = locate(href_list["toggle_blast_door"])
|
||||
if(!B)
|
||||
return
|
||||
spawn(0)
|
||||
if(B.density)
|
||||
B.open()
|
||||
else
|
||||
B.close()
|
||||
|
||||
|
||||
// Updates status displays with a new message
|
||||
// Copied from /obj/item/weapon/cartridge/proc/post_status(),
|
||||
// code/game/objects/items/devices/PDA/cart.dm, line 251
|
||||
/obj/item/weapon/commcard/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
|
||||
internal_data["stat_display_active1"] = data1 // Update the internally stored message, we won't get receive_signal if we're the sender
|
||||
internal_data["stat_display_active2"] = data2
|
||||
if(loc)
|
||||
var/obj/item/PDA = loc
|
||||
var/mob/user = PDA.fingerprintslast
|
||||
log_admin("STATUS: [user] set status screen with [src]. Message: [data1] [data2]")
|
||||
message_admins("STATUS: [user] set status screen with [src]. Message: [data1] [data2]")
|
||||
|
||||
if("alert")
|
||||
status_signal.data["picture_state"] = data1
|
||||
|
||||
frequency.post_signal(src, status_signal)
|
||||
|
||||
// Receives updates by external devices to the status displays
|
||||
/obj/item/weapon/commcard/receive_signal(var/datum/signal/signal, var/receive_method, var/receive_param)
|
||||
internal_data["stat_display_special"] = signal.data["command"]
|
||||
switch(signal.data["command"])
|
||||
if("message")
|
||||
internal_data["stat_display_active1"] = signal.data["msg1"]
|
||||
internal_data["stat_display_active2"] = signal.data["msg2"]
|
||||
if("alert")
|
||||
internal_data["stat_display_special"] = signal.data["picture_state"]
|
||||
|
||||
|
||||
///////////////////////////
|
||||
// SUBTYPES
|
||||
///////////////////////////
|
||||
|
||||
|
||||
// Engineering Cartridge:
|
||||
// Devices
|
||||
// *- Halogen Counter
|
||||
// Templates
|
||||
// *- Power Monitor
|
||||
/obj/item/weapon/commcard/engineering
|
||||
name = "\improper Power-ON cartridge"
|
||||
icon_state = "cart-e"
|
||||
ui_templates = list(list("name" = "Power Monitor", "template" = "comm_power_monitor.tmpl"))
|
||||
|
||||
/obj/item/weapon/commcard/engineering/New()
|
||||
..()
|
||||
internal_devices |= new /obj/item/device/halogen_counter(src)
|
||||
|
||||
/obj/item/weapon/commcard/engineering/initialize()
|
||||
internal_data["grid_sensors"] = find_powernet_sensors()
|
||||
internal_data["powernet_target"] = ""
|
||||
|
||||
/obj/item/weapon/commcard/engineering/get_data()
|
||||
return list(
|
||||
list("field" = "powernet_monitoring", "value" = get_powernet_monitoring_list()),
|
||||
list("field" = "powernet_target", "value" = get_powernet_target(internal_data["powernet_target"]))
|
||||
)
|
||||
|
||||
// Atmospherics Cartridge:
|
||||
// Devices
|
||||
// *- Gas scanner
|
||||
/obj/item/weapon/commcard/atmos
|
||||
name = "\improper BreatheDeep cartridge"
|
||||
icon_state = "cart-a"
|
||||
|
||||
/obj/item/weapon/commcard/atmos/New()
|
||||
..()
|
||||
internal_devices |= new /obj/item/device/analyzer(src)
|
||||
|
||||
|
||||
// Medical Cartridge:
|
||||
// Devices
|
||||
// *- Halogen Counter
|
||||
// *- Health Analyzer
|
||||
// Templates
|
||||
// *- Medical Records
|
||||
/obj/item/weapon/commcard/medical
|
||||
name = "\improper Med-U cartridge"
|
||||
icon_state = "cart-m"
|
||||
ui_templates = list(list("name" = "Medical Records", "template" = "med_records.tmpl"))
|
||||
|
||||
/obj/item/weapon/commcard/medical/New()
|
||||
..()
|
||||
internal_devices |= new /obj/item/device/healthanalyzer(src)
|
||||
internal_devices |= new /obj/item/device/halogen_counter(src)
|
||||
|
||||
/obj/item/weapon/commcard/medical/get_data()
|
||||
return list(list("field" = "med_records", "value" = get_med_records()))
|
||||
|
||||
|
||||
// Chemistry Cartridge:
|
||||
// Devices
|
||||
// *- Halogen Counter
|
||||
// *- Health Analyzer
|
||||
// *- Reagent Scanner
|
||||
// Templates
|
||||
// *- Medical Records
|
||||
/obj/item/weapon/commcard/medical/chemistry
|
||||
name = "\improper ChemWhiz cartridge"
|
||||
icon_state = "cart-chem"
|
||||
|
||||
/obj/item/weapon/commcard/medical/chemistry/New()
|
||||
..()
|
||||
internal_devices |= new /obj/item/device/reagent_scanner(src)
|
||||
|
||||
|
||||
// Detective Cartridge:
|
||||
// Devices
|
||||
// *- Halogen Counter
|
||||
// *- Health Analyzer
|
||||
// Templates
|
||||
// *- Medical Records
|
||||
// *- Security Records
|
||||
/obj/item/weapon/commcard/medical/detective
|
||||
name = "\improper D.E.T.E.C.T. cartridge"
|
||||
icon_state = "cart-s"
|
||||
ui_templates = list(
|
||||
list("name" = "Medical Records", "template" = "med_records.tmpl"),
|
||||
list("name" = "Security Records", "template" = "sec_records.tmpl")
|
||||
)
|
||||
|
||||
/obj/item/weapon/commcard/medical/detective/get_data()
|
||||
var/list/data = ..()
|
||||
data[++data.len] = list("field" = "sec_records", "value" = get_sec_records())
|
||||
return data
|
||||
|
||||
|
||||
// Internal Affairs Cartridge:
|
||||
// Templates
|
||||
// *- Security Records
|
||||
// *- Employment Records
|
||||
/obj/item/weapon/commcard/int_aff
|
||||
name = "\improper P.R.O.V.E. cartridge"
|
||||
icon_state = "cart-s"
|
||||
ui_templates = list(
|
||||
list("name" = "Employment Records", "template" = "emp_records.tmpl"),
|
||||
list("name" = "Security Records", "template" = "sec_records.tmpl")
|
||||
)
|
||||
|
||||
/obj/item/weapon/commcard/int_aff/get_data()
|
||||
return list(
|
||||
list("field" = "emp_records", "value" = get_emp_records()),
|
||||
list("field" = "sec_records", "value" = get_sec_records())
|
||||
)
|
||||
|
||||
|
||||
// Security Cartridge:
|
||||
// Templates
|
||||
// *- Security Records
|
||||
// *- Security Bot Access
|
||||
/obj/item/weapon/commcard/security
|
||||
name = "\improper R.O.B.U.S.T. cartridge"
|
||||
icon_state = "cart-s"
|
||||
ui_templates = list(
|
||||
list("name" = "Security Records", "template" = "sec_records.tmpl"),
|
||||
list("name" = "Security Bot Control", "template" = "sec_bot_access.tmpl")
|
||||
)
|
||||
|
||||
/obj/item/weapon/commcard/security/get_data()
|
||||
return list(
|
||||
list("field" = "sec_records", "value" = get_sec_records()),
|
||||
list("field" = "sec_bot_access", "value" = get_sec_bot_access())
|
||||
)
|
||||
|
||||
|
||||
// Janitor Cartridge:
|
||||
// Templates
|
||||
// *- Janitorial Locator Magicbox
|
||||
/obj/item/weapon/commcard/janitor
|
||||
name = "\improper CustodiPRO cartridge"
|
||||
desc = "The ultimate in clean-room design."
|
||||
ui_templates = list(
|
||||
list("name" = "Janitorial Supply Locator", "template" = "janitorialLocator.tmpl")
|
||||
)
|
||||
|
||||
/obj/item/weapon/commcard/janitor/get_data()
|
||||
return list(
|
||||
list("field" = "janidata", "value" = get_janitorial_locations())
|
||||
)
|
||||
|
||||
|
||||
// Signal Cartridge:
|
||||
// Devices
|
||||
// *- Signaler
|
||||
// Templates
|
||||
// *- Signaler Access
|
||||
/obj/item/weapon/commcard/signal
|
||||
name = "generic signaler cartridge"
|
||||
desc = "A data cartridge with an integrated radio signaler module."
|
||||
ui_templates = list(
|
||||
list("name" = "Integrated Signaler Control", "template" = "signaler_access.tmpl")
|
||||
)
|
||||
|
||||
/obj/item/weapon/commcard/signal/New()
|
||||
..()
|
||||
internal_devices |= new /obj/item/device/assembly/signaler(src)
|
||||
|
||||
/obj/item/weapon/commcard/signal/get_data()
|
||||
return list(
|
||||
list("field" = "signaler_access", "value" = get_int_signalers())
|
||||
)
|
||||
|
||||
|
||||
// Science Cartridge:
|
||||
// Devices
|
||||
// *- Signaler
|
||||
// *- Reagent Scanner
|
||||
// *- Gas Scanner
|
||||
// Templates
|
||||
// *- Signaler Access
|
||||
/obj/item/weapon/commcard/signal/science
|
||||
name = "\improper Signal Ace 2 cartridge"
|
||||
desc = "Complete with integrated radio signaler!"
|
||||
icon_state = "cart-tox"
|
||||
// UI templates inherited
|
||||
|
||||
/obj/item/weapon/commcard/signal/science/New()
|
||||
..()
|
||||
internal_devices |= new /obj/item/device/reagent_scanner(src)
|
||||
internal_devices |= new /obj/item/device/analyzer(src)
|
||||
|
||||
|
||||
// Supply Cartridge:
|
||||
// Templates
|
||||
// *- Supply Records
|
||||
/obj/item/weapon/commcard/supply
|
||||
name = "\improper Space Parts & Space Vendors cartridge"
|
||||
desc = "Perfect for the Quartermaster on the go!"
|
||||
icon_state = "cart-q"
|
||||
ui_templates = list(
|
||||
list("name" = "Supply Records", "template" = "supply_records.tmpl")
|
||||
)
|
||||
|
||||
/obj/item/weapon/commcard/supply/New()
|
||||
..()
|
||||
internal_data["supply_category"] = null
|
||||
internal_data["supply_controls"] = FALSE // Cannot control the supply shuttle, cannot accept orders
|
||||
internal_data["supply_pack_expanded"] = list()
|
||||
internal_data["supply_reqtime"] = -1
|
||||
|
||||
/obj/item/weapon/commcard/supply/get_data()
|
||||
// Supply records data
|
||||
var/list/shuttle_status = get_supply_shuttle_status()
|
||||
var/list/orders = get_supply_orders()
|
||||
var/list/receipts = get_supply_receipts()
|
||||
var/list/misc_supply_data = get_misc_supply_data() // Packaging this stuff externally so it's less hardcoded into the specific cartridge
|
||||
var/list/pack_list = list() // List of supply packs within the currently selected category
|
||||
|
||||
if(internal_data["supply_category"])
|
||||
pack_list = get_supply_pack_list()
|
||||
|
||||
return list(
|
||||
list("field" = "shuttle_auth", "value" = misc_supply_data["shuttle_auth"]),
|
||||
list("field" = "order_auth", "value" = misc_supply_data["order_auth"]),
|
||||
list("field" = "supply_points", "value" = misc_supply_data["supply_points"]),
|
||||
list("field" = "categories", "value" = misc_supply_data["supply_categories"]),
|
||||
list("field" = "contraband", "value" = misc_supply_data["contraband"]),
|
||||
list("field" = "active_category", "value" = internal_data["supply_category"]),
|
||||
list("field" = "shuttle", "value" = shuttle_status),
|
||||
list("field" = "orders", "value" = orders),
|
||||
list("field" = "receipts", "value" = receipts),
|
||||
list("field" = "supply_packs", "value" = pack_list)
|
||||
)
|
||||
|
||||
|
||||
// Command Cartridge:
|
||||
// Templates
|
||||
// *- Status Display Access
|
||||
// *- Employment Records
|
||||
/obj/item/weapon/commcard/head
|
||||
name = "\improper Easy-Record DELUXE"
|
||||
icon_state = "cart-h"
|
||||
ui_templates = list(
|
||||
list("name" = "Status Display Access", "template" = "stat_display_access.tmpl"),
|
||||
list("name" = "Employment Records", "template" = "emp_records.tmpl")
|
||||
)
|
||||
|
||||
/obj/item/weapon/commcard/head/New()
|
||||
..()
|
||||
internal_data["stat_display_line1"] = null
|
||||
internal_data["stat_display_line2"] = null
|
||||
internal_data["stat_display_active1"] = null
|
||||
internal_data["stat_display_active2"] = null
|
||||
internal_data["stat_display_special"] = null
|
||||
|
||||
/obj/item/weapon/commcard/head/initialize()
|
||||
// Have to register the commcard with the Radio controller to receive updates to the status displays
|
||||
radio_controller.add_object(src, 1435)
|
||||
..()
|
||||
|
||||
/obj/item/weapon/commcard/head/Destroy()
|
||||
// Have to unregister the commcard for proper bookkeeping
|
||||
radio_controller.remove_object(src, 1435)
|
||||
..()
|
||||
|
||||
/obj/item/weapon/commcard/head/get_data()
|
||||
return list(
|
||||
list("field" = "emp_records", "value" = get_emp_records()),
|
||||
list("field" = "stat_display", "value" = get_status_display())
|
||||
)
|
||||
|
||||
// Head of Personnel Cartridge:
|
||||
// Templates
|
||||
// *- Status Display Access
|
||||
// *- Employment Records
|
||||
// *- Security Records
|
||||
// *- Supply Records
|
||||
// ?- Supply Bot Access
|
||||
// *- Janitorial Locator Magicbox
|
||||
/obj/item/weapon/commcard/head/hop
|
||||
name = "\improper HumanResources9001 cartridge"
|
||||
icon_state = "cart-h"
|
||||
ui_templates = list(
|
||||
list("name" = "Status Display Access", "template" = "stat_display_access.tmpl"),
|
||||
list("name" = "Employment Records", "template" = "emp_records.tmpl"),
|
||||
list("name" = "Security Records", "template" = "sec_records.tmpl"),
|
||||
list("name" = "Supply Records", "template" = "supply_records.tmpl"),
|
||||
list("name" = "Janitorial Supply Locator", "template" = "janitorialLocator.tmpl")
|
||||
)
|
||||
|
||||
|
||||
/obj/item/weapon/commcard/head/hop/get_data()
|
||||
var/list/data = ..()
|
||||
|
||||
// Sec records
|
||||
data[++data.len] = list("field" = "sec_records", "value" = get_sec_records())
|
||||
|
||||
// Supply records data
|
||||
var/list/shuttle_status = get_supply_shuttle_status()
|
||||
var/list/orders = get_supply_orders()
|
||||
var/list/receipts = get_supply_receipts()
|
||||
var/list/misc_supply_data = get_misc_supply_data() // Packaging this stuff externally so it's less hardcoded into the specific cartridge
|
||||
var/list/pack_list = list() // List of supply packs within the currently selected category
|
||||
|
||||
if(internal_data["supply_category"])
|
||||
pack_list = get_supply_pack_list()
|
||||
|
||||
data[++data.len] = list("field" = "shuttle_auth", "value" = misc_supply_data["shuttle_auth"])
|
||||
data[++data.len] = list("field" = "order_auth", "value" = misc_supply_data["order_auth"])
|
||||
data[++data.len] = list("field" = "supply_points", "value" = misc_supply_data["supply_points"])
|
||||
data[++data.len] = list("field" = "categories", "value" = misc_supply_data["supply_categories"])
|
||||
data[++data.len] = list("field" = "contraband", "value" = misc_supply_data["contraband"])
|
||||
data[++data.len] = list("field" = "active_category", "value" = internal_data["supply_category"])
|
||||
data[++data.len] = list("field" = "shuttle", "value" = shuttle_status)
|
||||
data[++data.len] = list("field" = "orders", "value" = orders)
|
||||
data[++data.len] = list("field" = "receipts", "value" = receipts)
|
||||
data[++data.len] = list("field" = "supply_packs", "value" = pack_list)
|
||||
|
||||
// Janitorial locator magicbox
|
||||
data[++data.len] = list("field" = "janidata", "value" = get_janitorial_locations())
|
||||
|
||||
return data
|
||||
|
||||
|
||||
// Head of Security Cartridge:
|
||||
// Templates
|
||||
// *- Status Display Access
|
||||
// *- Employment Records
|
||||
// *- Security Records
|
||||
// *- Security Bot Access
|
||||
/obj/item/weapon/commcard/head/hos
|
||||
name = "\improper R.O.B.U.S.T. DELUXE"
|
||||
icon_state = "cart-hos"
|
||||
ui_templates = list(
|
||||
list("name" = "Status Display Access", "template" = "stat_display_access.tmpl"),
|
||||
list("name" = "Employment Records", "template" = "emp_records.tmpl"),
|
||||
list("name" = "Security Records", "template" = "sec_records.tmpl"),
|
||||
list("name" = "Security Bot Control", "template" = "sec_bot_access.tmpl")
|
||||
)
|
||||
|
||||
/obj/item/weapon/commcard/head/hos/get_data()
|
||||
var/list/data = ..()
|
||||
// Sec records
|
||||
data[++data.len] = list("field" = "sec_records", "value" = get_sec_records())
|
||||
// Sec bot access
|
||||
data[++data.len] = list("field" = "sec_bot_access", "value" = get_sec_bot_access())
|
||||
return data
|
||||
|
||||
|
||||
// Research Director Cartridge:
|
||||
// Devices
|
||||
// *- Signaler
|
||||
// *- Gas Scanner
|
||||
// *- Reagent Scanner
|
||||
// Templates
|
||||
// *- Status Display Access
|
||||
// *- Employment Records
|
||||
// *- Signaler Access
|
||||
/obj/item/weapon/commcard/head/rd
|
||||
name = "\improper Signal Ace DELUXE"
|
||||
icon_state = "cart-rd"
|
||||
ui_templates = list(
|
||||
list("name" = "Status Display Access", "template" = "stat_display_access.tmpl"),
|
||||
list("name" = "Employment Records", "template" = "emp_records.tmpl"),
|
||||
list("name" = "Integrated Signaler Control", "template" = "signaler_access.tmpl")
|
||||
)
|
||||
|
||||
/obj/item/weapon/commcard/head/rd/New()
|
||||
..()
|
||||
internal_devices |= new /obj/item/device/analyzer(src)
|
||||
internal_devices |= new /obj/item/device/reagent_scanner(src)
|
||||
internal_devices |= new /obj/item/device/assembly/signaler(src)
|
||||
|
||||
/obj/item/weapon/commcard/head/rd/get_data()
|
||||
var/list/data = ..()
|
||||
// Signaler access
|
||||
data[++data.len] = list("field" = "signaler_access", "value" = get_int_signalers())
|
||||
return data
|
||||
|
||||
|
||||
// Chief Medical Officer Cartridge:
|
||||
// Devices
|
||||
// *- Health Analyzer
|
||||
// *- Reagent Scanner
|
||||
// *- Halogen Counter
|
||||
// Templates
|
||||
// *- Status Display Access
|
||||
// *- Employment Records
|
||||
// *- Medical Records
|
||||
/obj/item/weapon/commcard/head/cmo
|
||||
name = "\improper Med-U DELUXE"
|
||||
icon_state = "cart-cmo"
|
||||
ui_templates = list(
|
||||
list("name" = "Status Display Access", "template" = "stat_display_access.tmpl"),
|
||||
list("name" = "Employment Records", "template" = "emp_records.tmpl"),
|
||||
list("name" = "Medical Records", "template" = "med_records.tmpl")
|
||||
)
|
||||
|
||||
/obj/item/weapon/commcard/head/cmo/New()
|
||||
..()
|
||||
internal_devices |= new /obj/item/device/healthanalyzer(src)
|
||||
internal_devices |= new /obj/item/device/reagent_scanner(src)
|
||||
internal_devices |= new /obj/item/device/halogen_counter(src)
|
||||
|
||||
/obj/item/weapon/commcard/head/cmo/get_data()
|
||||
var/list/data = ..()
|
||||
// Med records
|
||||
data[++data.len] = list("field" = "med_records", "value" = get_med_records())
|
||||
return data
|
||||
|
||||
// Chief Engineer Cartridge:
|
||||
// Devices
|
||||
// *- Gas Scanner
|
||||
// *- Halogen Counter
|
||||
// Templates
|
||||
// *- Status Display Access
|
||||
// *- Employment Records
|
||||
// *- Power Monitoring
|
||||
/obj/item/weapon/commcard/head/ce
|
||||
name = "\improper Power-On DELUXE"
|
||||
icon_state = "cart-ce"
|
||||
ui_templates = list(
|
||||
list("name" = "Status Display Access", "template" = "stat_display_access.tmpl"),
|
||||
list("name" = "Employment Records", "template" = "emp_records.tmpl"),
|
||||
list("name" = "Power Monitor", "template" = "comm_power_monitor.tmpl")
|
||||
)
|
||||
|
||||
/obj/item/weapon/commcard/head/ce/New()
|
||||
..()
|
||||
internal_devices |= new /obj.item/device/analyzer(src)
|
||||
internal_devices |= new /obj/item/device/halogen_counter(src)
|
||||
|
||||
/obj/item/weapon/commcard/head/ce/initialize()
|
||||
internal_data["grid_sensors"] = find_powernet_sensors()
|
||||
internal_data["powernet_target"] = ""
|
||||
|
||||
/obj/item/weapon/commcard/head/ce/get_data()
|
||||
var/list/data = ..()
|
||||
// Add power monitoring data
|
||||
data[++data.len] = list("field" = "powernet_monitoring", "value" = get_powernet_monitoring_list())
|
||||
data[++data.len] = list("field" = "powernet_target", "value" = get_powernet_target(internal_data["powernet_target"]))
|
||||
return data
|
||||
|
||||
|
||||
// Captain Cartridge:
|
||||
// Devices
|
||||
// *- Health analyzer
|
||||
// *- Gas Scanner
|
||||
// *- Reagent Scanner
|
||||
// *- Halogen Counter
|
||||
// X- GPS - Balance
|
||||
// *- Signaler
|
||||
// Templates
|
||||
// *- Status Display Access
|
||||
// *- Employment Records
|
||||
// *- Medical Records
|
||||
// *- Security Records
|
||||
// *- Power Monitoring
|
||||
// *- Supply Records
|
||||
// X- Supply Bot Access - Mulebots usually break when used
|
||||
// *- Security Bot Access
|
||||
// *- Janitorial Locator Magicbox
|
||||
// X- GPS Access - Balance
|
||||
// *- Signaler Access
|
||||
/obj/item/weapon/commcard/head/captain
|
||||
name = "\improper Value-PAK cartridge"
|
||||
desc = "Now with 200% more value!"
|
||||
icon_state = "cart-c"
|
||||
ui_templates = list(
|
||||
list("name" = "Status Display Access", "template" = "stat_display_access.tmpl"),
|
||||
list("name" = "Employment Records", "template" = "emp_records.tmpl"),
|
||||
list("name" = "Medical Records", "template" = "med_records.tmpl"),
|
||||
list("name" = "Security Records", "template" = "sec_records.tmpl"),
|
||||
list("name" = "Security Bot Control", "template" = "sec_bot_access.tmpl"),
|
||||
list("name" = "Power Monitor", "template" = "comm_power_monitor.tmpl"),
|
||||
list("name" = "Supply Records", "template" = "supply_records.tmpl"),
|
||||
list("name" = "Janitorial Supply Locator", "template" = "janitorialLocator.tmpl"),
|
||||
list("name" = "Integrated Signaler Control", "template" = "signaler_access.tmpl")
|
||||
)
|
||||
|
||||
/obj/item/weapon/commcard/head/captain/New()
|
||||
..()
|
||||
internal_devices |= new /obj.item/device/analyzer(src)
|
||||
internal_devices |= new /obj/item/device/healthanalyzer(src)
|
||||
internal_devices |= new /obj/item/device/reagent_scanner(src)
|
||||
internal_devices |= new /obj/item/device/halogen_counter(src)
|
||||
internal_devices |= new /obj/item/device/assembly/signaler(src)
|
||||
|
||||
/obj/item/weapon/commcard/head/captain/get_data()
|
||||
var/list/data = ..()
|
||||
//Med records
|
||||
data[++data.len] = list("field" = "med_records", "value" = get_med_records())
|
||||
|
||||
// Sec records
|
||||
data[++data.len] = list("field" = "sec_records", "value" = get_sec_records())
|
||||
|
||||
// Sec bot access
|
||||
data[++data.len] = list("field" = "sec_bot_access", "value" = get_sec_bot_access())
|
||||
|
||||
// Power Monitoring
|
||||
data[++data.len] = list("field" = "powernet_monitoring", "value" = get_powernet_monitoring_list())
|
||||
data[++data.len] = list("field" = "powernet_target", "value" = get_powernet_target(internal_data["powernet_target"]))
|
||||
|
||||
// Supply records data
|
||||
var/list/shuttle_status = get_supply_shuttle_status()
|
||||
var/list/orders = get_supply_orders()
|
||||
var/list/receipts = get_supply_receipts()
|
||||
var/list/misc_supply_data = get_misc_supply_data() // Packaging this stuff externally so it's less hardcoded into the specific cartridge
|
||||
var/list/pack_list = list() // List of supply packs within the currently selected category
|
||||
|
||||
if(internal_data["supply_category"])
|
||||
pack_list = get_supply_pack_list()
|
||||
|
||||
data[++data.len] = list("field" = "shuttle_auth", "value" = misc_supply_data["shuttle_auth"])
|
||||
data[++data.len] = list("field" = "order_auth", "value" = misc_supply_data["order_auth"])
|
||||
data[++data.len] = list("field" = "supply_points", "value" = misc_supply_data["supply_points"])
|
||||
data[++data.len] = list("field" = "categories", "value" = misc_supply_data["supply_categories"])
|
||||
data[++data.len] = list("field" = "contraband", "value" = misc_supply_data["contraband"])
|
||||
data[++data.len] = list("field" = "active_category", "value" = internal_data["supply_category"])
|
||||
data[++data.len] = list("field" = "shuttle", "value" = shuttle_status)
|
||||
data[++data.len] = list("field" = "orders", "value" = orders)
|
||||
data[++data.len] = list("field" = "receipts", "value" = receipts)
|
||||
data[++data.len] = list("field" = "supply_packs", "value" = pack_list)
|
||||
|
||||
// Janitorial locator magicbox
|
||||
data[++data.len] = list("field" = "janidata", "value" = get_janitorial_locations())
|
||||
|
||||
// Signaler access
|
||||
data[++data.len] = list("field" = "signaler_access", "value" = get_int_signalers())
|
||||
|
||||
return data
|
||||
|
||||
|
||||
// Mercenary Cartridge
|
||||
// Templates
|
||||
// *- Merc Shuttle Door Controller
|
||||
/obj/item/weapon/commcard/mercenary
|
||||
name = "\improper Detomatix cartridge"
|
||||
icon_state = "cart"
|
||||
ui_templates = list(
|
||||
list("name" = "Shuttle Blast Door Control", "template" = "merc_blast_door_control.tmpl")
|
||||
)
|
||||
|
||||
/obj/item/weapon/commcard/mercenary/initialize()
|
||||
internal_data["shuttle_door_code"] = "smindicate" // Copied from PDA code
|
||||
internal_data["shuttle_doors"] = find_blast_doors()
|
||||
|
||||
/obj/item/weapon/commcard/mercenary/get_data()
|
||||
var/door_status[0]
|
||||
for(var/obj/machinery/door/blast/B in internal_data["shuttle_doors"])
|
||||
door_status[++door_status.len] += list(
|
||||
"open" = B.density,
|
||||
"name" = B.name,
|
||||
"ref" = "\ref[B]"
|
||||
)
|
||||
|
||||
return list(
|
||||
list("field" = "blast_door", "value" = door_status)
|
||||
)
|
||||
|
||||
|
||||
// Explorer Cartridge
|
||||
// Devices
|
||||
// *- GPS
|
||||
// Templates
|
||||
// *- GPS Access
|
||||
|
||||
// IMPORTANT: NOT MAPPED IN DUE TO BALANCE CONCERNS RE: FINDING THE VICTIMS OF ANTAGS.
|
||||
// See suit sensors, specifically ease of turning them off, and variable level of settings which may or may not give location
|
||||
// A GPS in your phone that is either broadcasting position or totally off, and can be hidden in pockets, coats, bags, boxes, etc, is much harder to disable
|
||||
/obj/item/weapon/commcard/explorer
|
||||
name = "\improper Explorator cartridge"
|
||||
icon_state = "cart-tox"
|
||||
ui_templates = list(
|
||||
list("name" = "Integrated GPS", "template" = "gps_access.tmpl")
|
||||
)
|
||||
|
||||
/obj/item/weapon/commcard/explorer/New()
|
||||
..()
|
||||
internal_devices |= new /obj/item/device/gps/explorer(src)
|
||||
|
||||
/obj/item/weapon/commcard/explorer/get_data()
|
||||
var/list/GPS = get_GPS_lists()
|
||||
|
||||
return list(
|
||||
list("field" = "gps_access", "value" = GPS[1]),
|
||||
list("field" = "gps_signal", "value" = GPS[2]),
|
||||
list("field" = "gps_status", "value" = GPS[3])
|
||||
)
|
||||
@@ -4,6 +4,18 @@
|
||||
|
||||
var/global/list/obj/item/device/communicator/all_communicators = list()
|
||||
|
||||
// List of core tabs the communicator can switch to
|
||||
#define HOMETAB 1
|
||||
#define PHONTAB 2
|
||||
#define CONTTAB 3
|
||||
#define MESSTAB 4
|
||||
#define NEWSTAB 5
|
||||
#define NOTETAB 6
|
||||
#define WTHRTAB 7
|
||||
#define MANITAB 8
|
||||
#define SETTTAB 9
|
||||
#define EXTRTAB 10
|
||||
|
||||
/obj/item/device/communicator
|
||||
name = "communicator"
|
||||
desc = "A personal device used to enable long range dialog between two people, utilizing existing telecommunications infrastructure to allow \
|
||||
@@ -31,20 +43,22 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
|
||||
var/note = "Thank you for choosing the T-14.2 Communicator, this is your notepad!" //Current note in the notepad function
|
||||
var/notehtml = ""
|
||||
|
||||
var/obj/item/weapon/cartridge/cartridge = null //current cartridge
|
||||
var/obj/item/weapon/commcard/cartridge = null //current cartridge
|
||||
var/fon = 0 // Internal light
|
||||
var/flum = 2 // Brightness
|
||||
|
||||
var/list/modules = list(
|
||||
list("module" = "Phone", "icon" = "phone64", "number" = 2),
|
||||
list("module" = "Contacts", "icon" = "person64", "number" = 3),
|
||||
list("module" = "Messaging", "icon" = "comment64", "number" = 4),
|
||||
list("module" = "Note", "icon" = "note64", "number" = 5),
|
||||
list("module" = "Weather", "icon" = "sun64", "number" = 6),
|
||||
list("module" = "Settings", "icon" = "gear64", "number" = 7)
|
||||
list("module" = "Phone", "icon" = "phone64", "number" = PHONTAB),
|
||||
list("module" = "Contacts", "icon" = "person64", "number" = CONTTAB),
|
||||
list("module" = "Messaging", "icon" = "comment64", "number" = MESSTAB),
|
||||
list("module" = "News", "icon" = "note64", "number" = NEWSTAB), // Need a different icon,
|
||||
list("module" = "Note", "icon" = "note64", "number" = NOTETAB),
|
||||
list("module" = "Weather", "icon" = "sun64", "number" = WTHRTAB),
|
||||
list("module" = "Crew Manifest", "icon" = "note64", "number" = MANITAB), // Need a different icon,
|
||||
list("module" = "Settings", "icon" = "gear64", "number" = SETTTAB),
|
||||
) //list("module" = "Name of Module", "icon" = "icon name64", "number" = "what tab is the module")
|
||||
|
||||
var/selected_tab = 1
|
||||
var/selected_tab = HOMETAB
|
||||
var/owner = ""
|
||||
var/occupation = ""
|
||||
var/alert_called = 0
|
||||
@@ -89,7 +103,7 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
|
||||
/obj/item/device/communicator/examine(mob/user)
|
||||
. = ..(user, 1)
|
||||
if(. && video_source)
|
||||
user << "<span class='notice'>It looks like it's on a video call: <a href='?src=\ref[src];watchvideo=1'>\[view\]</a></span>"
|
||||
to_chat(user, "<span class='notice'>It looks like it's on a video call: <a href='?src=\ref[src];watchvideo=1'>\[view\]</a></span>")
|
||||
|
||||
// Proc: initialize_exonet()
|
||||
// Parameters: 1 (user - the person the communicator belongs to)
|
||||
@@ -130,7 +144,7 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
|
||||
else
|
||||
msg += "<span class='notice'>The device doesn't appear to be transmitting any data.</span>\n"
|
||||
msg += "</span>"
|
||||
user << msg
|
||||
to_chat(user, msg)
|
||||
return
|
||||
|
||||
// Proc: emp_act()
|
||||
@@ -188,10 +202,22 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
|
||||
if(!get_connection_to_tcomms())
|
||||
close_connection(reason = "Connection timed out")
|
||||
|
||||
// Proc: attack()
|
||||
// Parameters: 2 (M - what is being attacked. user - the mob that has the communicator)
|
||||
// Description: When the communicator has an attached commcard with internal devices, relay the attack() through to those devices.
|
||||
// Contents of the for loop are copied from gripper code, because that does approximately what we want to do.
|
||||
/obj/item/device/communicator/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
|
||||
if(cartridge && cartridge.active_devices)
|
||||
for(var/obj/item/wrapped in cartridge.active_devices)
|
||||
if(wrapped) //The force of the wrapped obj gets set to zero during the attack() and afterattack().
|
||||
wrapped.attack(M,user)
|
||||
return 0
|
||||
|
||||
// Proc: attackby()
|
||||
// Parameters: 2 (C - what is used on the communicator. user - the mob that has the communicator)
|
||||
// Description: When an ID is swiped on the communicator, the communicator reads the job and checks it against the Owner name, if success, the occupation is added.
|
||||
/obj/item/device/communicator/attackby(obj/item/C as obj, mob/user as mob)
|
||||
..()
|
||||
if(istype(C, /obj/item/weapon/card/id))
|
||||
var/obj/item/weapon/card/id/idcard = C
|
||||
if(!idcard.registered_name || !idcard.assignment)
|
||||
@@ -201,12 +227,14 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
|
||||
else if(owner == idcard.registered_name)
|
||||
occupation = idcard.assignment
|
||||
to_chat(user, "<span class='notice'>Occupation updated.</span>")
|
||||
// else if(istype(C, /obj/item/weapon/cartridge))
|
||||
// if(cartridge)
|
||||
// to_chat(user, "<span class='notice'>\The [src] already has an external device attached!</span>")
|
||||
// else
|
||||
// modules.Add(list("module" = "External Device", "icon = external64", "number" = 8))
|
||||
// cartridge = C
|
||||
|
||||
if(istype(C, /obj/item/weapon/commcard) && !cartridge)
|
||||
cartridge = C
|
||||
user.drop_item()
|
||||
cartridge.forceMove(src)
|
||||
to_chat(usr, "<span class='notice'>You slot \the [cartridge] into \the [src].</span>")
|
||||
modules[++modules.len] = list("module" = "External Device", "icon" = "external64", "number" = EXTRTAB)
|
||||
GLOB.nanomanager.update_uis(src) // update all UIs attached to src
|
||||
return
|
||||
|
||||
// Proc: attack_self()
|
||||
@@ -330,6 +358,38 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
|
||||
client_huds |= global_hud.whitense
|
||||
client_huds |= global_hud.darkMask
|
||||
|
||||
/obj/item/device/communicator/verb/verb_remove_cartridge()
|
||||
set category = "Object"
|
||||
set name = "Remove commcard"
|
||||
set src in usr
|
||||
|
||||
// Can't remove what isn't there
|
||||
if(!cartridge)
|
||||
to_chat(usr, "<span class='notice'>There isn't a commcard to remove!</span>")
|
||||
return
|
||||
|
||||
// Can't remove if you're physically unable to
|
||||
if(usr.stat || usr.restrained() || usr.paralysis || usr.stunned || usr.weakened)
|
||||
to_chat(usr, "<span class='notice'>You cannot do this while restrained.</span>")
|
||||
return
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
cartridge.loc = T
|
||||
// If it's in someone, put the cartridge in their hands
|
||||
if (ismob(loc))
|
||||
var/mob/M = loc
|
||||
M.put_in_hands(cartridge)
|
||||
// Else just set it on the ground
|
||||
else
|
||||
cartridge.loc = get_turf(src)
|
||||
cartridge = null
|
||||
// We have to iterate through the modules to find EXTRTAB, because list procs don't play nice with a list of lists
|
||||
for(var/i = 1, i <= modules.len, i++)
|
||||
if(modules[i]["number"] == EXTRTAB)
|
||||
modules.Cut(i, i+1)
|
||||
break
|
||||
to_chat(usr, "<span class='notice'>You remove \the [cartridge] from the [name].</span>")
|
||||
|
||||
//It's the 26th century. We should have smart watches by now.
|
||||
/obj/item/device/communicator/watch
|
||||
name = "communicator watch"
|
||||
|
||||
@@ -11,17 +11,532 @@
|
||||
var/co2_level = environment.gas["carbon_dioxide"]/total_moles
|
||||
var/phoron_level = environment.gas["phoron"]/total_moles
|
||||
var/unknown_level = 1-(o2_level+n2_level+co2_level+phoron_level)
|
||||
|
||||
// Label is what the entry is describing
|
||||
// Type identifies which unit or other special characters to use
|
||||
// Val is the information reported
|
||||
// Bad_high/_low are the values outside of which the entry reports as dangerous
|
||||
// Poor_high/_low are the values outside of which the entry reports as unideal
|
||||
// Values were extracted from the template itself
|
||||
results = 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)]",
|
||||
"phoron" = "[round(phoron_level*100,0.01)]",
|
||||
"other" = "[round(unknown_level, 0.01)]",
|
||||
"temp" = "[round(environment.temperature-T0C,0.1)]",
|
||||
"reading" = 1
|
||||
list("entry" = "Pressure", "type" = "pressure", "val" = "[round(pressure,0.1)]", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80),
|
||||
list("entry" = "Temperature", "type" = "temp", "val" = "[round(environment.temperature-T0C,0.1)]", "bad_high" = 35, "poor_high" = 25, "poor_low" = 15, "bad_low" = 5),
|
||||
list("entry" = "Oxygen", "type" = "pressure", "val" = "[round(o2_level*100,0.1)]", "bad_high" = 140, "poor_high" = 135, "poor_low" = 19, "bad_low" = 17),
|
||||
list("entry" = "Nitrogen", "type" = "pressure", "val" = "[round(n2_level*100,0.1)]", "bad_high" = 105, "poor_high" = 85, "poor_low" = 50, "bad_low" = 40),
|
||||
list("entry" = "Carbon Dioxide", "type" = "pressure", "val" = "[round(co2_level*100,0.1)]", "bad_high" = 10, "poor_high" = 5, "poor_low" = 0, "bad_low" = 0),
|
||||
list("entry" = "Phoron", "type" = "pressure", "val" = "[round(phoron_level*100,0.01)]", "bad_high" = 0.5, "poor_high" = 0, "poor_low" = 0, "bad_low" = 0),
|
||||
list("entry" = "Other", "type" = "pressure", "val" = "[round(unknown_level, 0.01)]", "bad_high" = 1, "poor_high" = 0.5, "poor_low" = 0, "bad_low" = 0)
|
||||
)
|
||||
|
||||
if(isnull(results))
|
||||
results = list("reading" = 0)
|
||||
return results
|
||||
results = list(list("entry" = "pressure", "val" = "0"))
|
||||
return results
|
||||
|
||||
|
||||
// Proc - compile_news()
|
||||
// Parameters - none
|
||||
// Description - Returns the list of newsfeeds, compiled for template processing
|
||||
/obj/item/device/communicator/proc/compile_news()
|
||||
var/list/feeds = list()
|
||||
for(var/datum/feed_channel/channel in news_network.network_channels)
|
||||
var/list/messages = list()
|
||||
if(!channel.censored)
|
||||
var/index = 0
|
||||
for(var/datum/feed_message/FM in channel.messages)
|
||||
index++
|
||||
if(FM.img)
|
||||
usr << browse_rsc(FM.img, "pda_news_tmp_photo_[feeds["channel"]]_[index].png")
|
||||
// News stories are HTML-stripped but require newline replacement to be properly displayed in NanoUI
|
||||
var/body = replacetext(FM.body, "\n", "<br>")
|
||||
messages[++messages.len] = list(
|
||||
"author" = FM.author,
|
||||
"body" = body,
|
||||
"message_type" = FM.message_type,
|
||||
"time_stamp" = FM.time_stamp,
|
||||
"has_image" = (FM.img != null),
|
||||
"caption" = FM.caption,
|
||||
"index" = index
|
||||
)
|
||||
|
||||
feeds[++feeds.len] = list(
|
||||
"name" = channel.channel_name,
|
||||
"censored" = channel.censored,
|
||||
"author" = channel.author,
|
||||
"messages" = messages
|
||||
)
|
||||
return feeds
|
||||
|
||||
// Proc - get_recent_news()
|
||||
// Parameters - none
|
||||
// Description - Returns the latest three newscasts, compiled for template processing
|
||||
/obj/item/device/communicator/proc/get_recent_news()
|
||||
var/list/news = list()
|
||||
|
||||
// Compile all the newscasts
|
||||
for(var/datum/feed_channel/channel in news_network.network_channels)
|
||||
if(!channel.censored)
|
||||
for(var/datum/feed_message/FM in channel.messages)
|
||||
var/body = replacetext(FM.body, "\n", "<br>")
|
||||
news[++news.len] = list(
|
||||
"channel" = channel.channel_name,
|
||||
"author" = FM.author,
|
||||
"body" = body,
|
||||
"message_type" = FM.message_type,
|
||||
"time_stamp" = FM.time_stamp,
|
||||
"has_image" = (FM.img != null),
|
||||
"caption" = FM.caption,
|
||||
)
|
||||
|
||||
// Cut out all but the youngest three
|
||||
while(news.len > 3)
|
||||
var/oldest = min(news[0]["time_stamp"], news[1]["time_stamp"], news[2]["time_stamp"], news[3]["time_stamp"])
|
||||
for(var/i = 0, i < 4, i++)
|
||||
if(news[i]["time_stamp"] == oldest)
|
||||
news.Remove(news[i])
|
||||
|
||||
return news
|
||||
|
||||
|
||||
|
||||
// Putting the commcard data harvesting helpers here
|
||||
// Not ideal to put all the procs on the base type
|
||||
// but it may open options for adminbus,
|
||||
// And it saves duplicated code
|
||||
|
||||
|
||||
// Medical records
|
||||
/obj/item/weapon/commcard/proc/get_med_records()
|
||||
var/med_records[0]
|
||||
for(var/datum/data/record/M in sortRecord(data_core.medical))
|
||||
var/record[0]
|
||||
record[++record.len] = list("tab" = "Name", "val" = M.fields["name"])
|
||||
record[++record.len] = list("tab" = "ID", "val" = M.fields["id"])
|
||||
record[++record.len] = list("tab" = "Blood Type", "val" = M.fields["b_type"])
|
||||
record[++record.len] = list("tab" = "DNA #", "val" = M.fields["b_dna"])
|
||||
record[++record.len] = list("tab" = "Gender", "val" = M.fields["id_gender"])
|
||||
record[++record.len] = list("tab" = "Entity Classification", "val" = M.fields["brain_type"])
|
||||
record[++record.len] = list("tab" = "Minor Disorders", "val" = M.fields["mi_dis"])
|
||||
record[++record.len] = list("tab" = "Major Disorders", "val" = M.fields["ma_dis"])
|
||||
record[++record.len] = list("tab" = "Allergies", "val" = M.fields["alg"])
|
||||
record[++record.len] = list("tab" = "Condition", "val" = M.fields["cdi"])
|
||||
record[++record.len] = list("tab" = "Notes", "val" = M.fields["notes"])
|
||||
|
||||
med_records[++med_records.len] = list("name" = M.fields["name"], "record" = record)
|
||||
return med_records
|
||||
|
||||
|
||||
// Employment records
|
||||
/obj/item/weapon/commcard/proc/get_emp_records()
|
||||
var/emp_records[0]
|
||||
for(var/datum/data/record/G in sortRecord(data_core.general))
|
||||
var/record[0]
|
||||
record[++record.len] = list("tab" = "Name", "val" = G.fields["name"])
|
||||
record[++record.len] = list("tab" = "ID", "val" = G.fields["id"])
|
||||
record[++record.len] = list("tab" = "Rank", "val" = G.fields["rank"])
|
||||
record[++record.len] = list("tab" = "Fingerprint", "val" = G.fields["fingerprint"])
|
||||
record[++record.len] = list("tab" = "Entity Classification", "val" = G.fields["brain_type"])
|
||||
record[++record.len] = list("tab" = "Sex", "val" = G.fields["sex"])
|
||||
record[++record.len] = list("tab" = "Species", "val" = G.fields["species"])
|
||||
record[++record.len] = list("tab" = "Age", "val" = G.fields["age"])
|
||||
record[++record.len] = list("tab" = "Notes", "val" = G.fields["notes"])
|
||||
|
||||
emp_records[++emp_records.len] = list("name" = G.fields["name"], "record" = record)
|
||||
return emp_records
|
||||
|
||||
|
||||
// Security records
|
||||
/obj/item/weapon/commcard/proc/get_sec_records()
|
||||
var/sec_records[0]
|
||||
for(var/datum/data/record/G in sortRecord(data_core.general))
|
||||
var/record[0]
|
||||
record[++record.len] = list("tab" = "Name", "val" = G.fields[""])
|
||||
record[++record.len] = list("tab" = "Sex", "val" = G.fields[""])
|
||||
record[++record.len] = list("tab" = "Species", "val" = G.fields[""])
|
||||
record[++record.len] = list("tab" = "Age", "val" = G.fields[""])
|
||||
record[++record.len] = list("tab" = "Rank", "val" = G.fields[""])
|
||||
record[++record.len] = list("tab" = "Fingerprint", "val" = G.fields[""])
|
||||
record[++record.len] = list("tab" = "Physical Status", "val" = G.fields[""])
|
||||
record[++record.len] = list("tab" = "Mental Status", "val" = G.fields[""])
|
||||
record[++record.len] = list("tab" = "Criminal Status", "val" = G.fields[""])
|
||||
record[++record.len] = list("tab" = "Major Crimes", "val" = G.fields[""])
|
||||
record[++record.len] = list("tab" = "Minor Crimes", "val" = G.fields[""])
|
||||
record[++record.len] = list("tab" = "Notes", "val" = G.fields["notes"])
|
||||
|
||||
sec_records[++sec_records.len] = list("name" = G.fields["name"], "record" = record)
|
||||
return sec_records
|
||||
|
||||
|
||||
// Status of all secbots
|
||||
// Weaker than what PDAs appear to do, but as of 7/1/2018 PDA secbot access is nonfunctional
|
||||
/obj/item/weapon/commcard/proc/get_sec_bot_access()
|
||||
var/sec_bots[0]
|
||||
for(var/mob/living/bot/secbot/S in mob_list)
|
||||
// Get new bot
|
||||
var/status[0]
|
||||
status[++status.len] = list("tab" = "Name", "val" = sanitize(S.name))
|
||||
|
||||
// If it's turned off, then it shouldn't be broadcasting any further info
|
||||
if(!S.on)
|
||||
status[++status.len] = list("tab" = "Power", "val" = "<span class='bad'>Off</span>") // Encoding the span classes here so I don't have to do complicated switches in the ui template
|
||||
continue
|
||||
status[++status.len] = list("tab" = "Power", "val" = "<span class='good'>On</span>")
|
||||
|
||||
// -- What it's doing
|
||||
// If it's engaged, then say who it thinks it's engaging
|
||||
if(S.target)
|
||||
status[++status.len] = list("tab" = "Status", "val" = "<span class='bad'>Apprehending Target</span>")
|
||||
status[++status.len] = list("tab" = "Target", "val" = S.target_name(S.target))
|
||||
// Else if it's patrolling
|
||||
else if(S.will_patrol)
|
||||
status[++status.len] = list("tab" = "Status", "val" = "<span class='good'>Patrolling</span>")
|
||||
// Otherwise we don't know what it's doing
|
||||
else
|
||||
status[++status.len] = list("tab" = "Status", "val" = "<span class='average'>Idle</span>")
|
||||
|
||||
// Where it is
|
||||
status[++status.len] = list("tab" = "Location", "val" = sanitize("[get_area(S.loc)]"))
|
||||
|
||||
// Append bot to the list
|
||||
sec_bots[++sec_bots.len] = list("bot" = S.name, "status" = status)
|
||||
return sec_bots
|
||||
|
||||
|
||||
// Code and frequency of stored signalers
|
||||
// Supports multiple signalers within the device
|
||||
/obj/item/weapon/commcard/proc/get_int_signalers()
|
||||
var/signalers[0]
|
||||
for(var/obj/item/device/assembly/signaler/S in internal_devices)
|
||||
var/unit[0]
|
||||
unit[++unit.len] = list("tab" = "Code", "val" = S.code)
|
||||
unit[++unit.len] = list("tab" = "Frequency", "val" = S.frequency)
|
||||
|
||||
signalers[++signalers.len] = list("ref" = "\ref[S]", "status" = unit)
|
||||
|
||||
return signalers
|
||||
|
||||
// Returns list of all powernet sensors currently visible to the commcard
|
||||
/obj/item/weapon/commcard/proc/find_powernet_sensors()
|
||||
var/grid_sensors[0]
|
||||
|
||||
// Find all the powernet sensors we need to pull data from
|
||||
// Copied from /datum/nano_module/power_monitor/proc/refresh_sensors(),
|
||||
// located in '/code/modules/nano/modules/power_monitor.dm'
|
||||
// Minor tweaks for efficiency and cleanliness
|
||||
var/turf/T = get_turf(src)
|
||||
if(T)
|
||||
var/list/levels = using_map.get_map_levels(T.z, FALSE)
|
||||
for(var/obj/machinery/power/sensor/S in machines)
|
||||
if((S.long_range) || (S.loc.z in levels) || (S.loc.z == T.z)) // Consoles have range on their Z-Level. Sensors with long_range var will work between Z levels.
|
||||
if(S.name_tag == "#UNKN#") // Default name. Shouldn't happen!
|
||||
warning("Powernet sensor with unset ID Tag! [S.x]X [S.y]Y [S.z]Z")
|
||||
else
|
||||
grid_sensors += S
|
||||
return grid_sensors
|
||||
|
||||
// List of powernets
|
||||
/obj/item/weapon/commcard/proc/get_powernet_monitoring_list()
|
||||
// Fetch power monitor data
|
||||
var/sensors[0]
|
||||
|
||||
for(var/obj/machinery/power/sensor/S in internal_data["grid_sensors"])
|
||||
var/list/focus = S.return_reading_data()
|
||||
|
||||
sensors[++sensors.len] = list(
|
||||
"name" = S.name_tag,
|
||||
"alarm" = focus["alarm"]
|
||||
)
|
||||
|
||||
return sensors
|
||||
|
||||
// Information about the targeted powernet
|
||||
/obj/item/weapon/commcard/proc/get_powernet_target(var/target_sensor)
|
||||
if(!target_sensor)
|
||||
return
|
||||
|
||||
var/powernet_target[0]
|
||||
|
||||
for(var/obj/machinery/power/sensor/S in internal_data["grid_sensors"])
|
||||
var/list/focus = S.return_reading_data()
|
||||
|
||||
// Packages the span class here so it doesn't need to be interpreted w/in the for loop in the ui template
|
||||
var/load_stat = "<span class='good'>Optimal</span>"
|
||||
if(focus["load_percentage"] >= 95)
|
||||
load_stat = "<span class='bad'>DANGER: Overload</span>"
|
||||
else if(focus["load_percentage"] >= 85)
|
||||
load_stat = "<span class='average'>WARNING: High Load</span>"
|
||||
|
||||
var/alarm_stat = focus["alarm"] ? "<span class='bad'>WARNING: Abnormal activity detected!</span>" : "<span class='good'>Secure</span>"
|
||||
|
||||
if(target_sensor == S.name_tag)
|
||||
powernet_target = list(
|
||||
"name" = S.name_tag,
|
||||
"alarm" = focus["alarm"],
|
||||
"error" = focus["error"],
|
||||
"apc_data" = focus["apc_data"],
|
||||
"status" = list(
|
||||
list("field" = "Network Load Status", "statval" = load_stat),
|
||||
list("field" = "Network Security Status", "statval" = alarm_stat),
|
||||
list("field" = "Load Percentage", "statval" = focus["load_percentage"]),
|
||||
list("field" = "Available Power", "statval" = focus["total_avail"]),
|
||||
list("field" = "APC Power Usage", "statval" = focus["total_used_apc"]),
|
||||
list("field" = "Other Power Usage", "statval" = focus["total_used_other"]),
|
||||
list("field" = "Total Usage", "statval" = focus["total_used_all"])
|
||||
)
|
||||
)
|
||||
|
||||
return powernet_target
|
||||
|
||||
// Compiles the locations of all janitorial paraphernalia, as used by janitorialLocator.tmpl
|
||||
/obj/item/weapon/commcard/proc/get_janitorial_locations()
|
||||
// Fetch janitorial locator
|
||||
var/janidata[0]
|
||||
var/list/cleaningList = list()
|
||||
cleaningList += all_mops + all_mopbuckets + all_janitorial_carts
|
||||
|
||||
// User's location
|
||||
var/turf/userloc = get_turf(src)
|
||||
if(isturf(userloc))
|
||||
janidata[++janidata.len] = list("field" = "Current Location", "val" = "<span class='good'>[userloc.x], [userloc.y], [using_map.get_zlevel_name(userloc.z)]</span>")
|
||||
else
|
||||
janidata[++janidata.len] = list("field" = "Current Location", "val" = "<span class='bad'>Unknown</span>")
|
||||
return janidata // If the user isn't on a valid turf, then it shouldn't be able to find anything anyways
|
||||
|
||||
// Mops, mop buckets, janitorial carts.
|
||||
for(var/obj/C in cleaningList)
|
||||
var/turf/T = get_turf(C)
|
||||
if(isturf(T) )//&& T.z in using_map.get_map_levels(userloc, FALSE))
|
||||
if(T.z == userloc.z)
|
||||
janidata[++janidata.len] = list("field" = apply_text_macros("\proper [C.name]"), "val" = "<span class='good'>[T.x], [T.y], [using_map.get_zlevel_name(T.z)]</span>")
|
||||
else
|
||||
janidata[++janidata.len] = list("field" = apply_text_macros("\proper [C.name]"), "val" = "<span class='average'>[T.x], [T.y], [using_map.get_zlevel_name(T.z)]</span>")
|
||||
|
||||
// Cleanbots
|
||||
for(var/mob/living/bot/cleanbot/B in living_mob_list)
|
||||
var/turf/T = get_turf(B)
|
||||
if(isturf(T) )//&& T.z in using_map.get_map_levels(userloc, FALSE))
|
||||
var/textout = ""
|
||||
if(B.on)
|
||||
textout += "Status: <span class='good'>Online</span><br>"
|
||||
if(T.z == userloc.z)
|
||||
textout += "<span class='good'>[T.x], [T.y], [using_map.get_zlevel_name(T.z)]</span>"
|
||||
else
|
||||
textout += "<span class='average'>[T.x], [T.y], [using_map.get_zlevel_name(T.z)]</span>"
|
||||
else
|
||||
textout += "Status: <span class='bad'>Offline</span>"
|
||||
|
||||
janidata[++janidata.len] = list("field" = "[B.name]", "val" = textout)
|
||||
|
||||
return janidata
|
||||
|
||||
// Compiles the three lists used by GPS_access.tmpl
|
||||
// The contents of the three lists are inherently related, so separating them into different procs would be largely redundant
|
||||
/obj/item/weapon/commcard/proc/get_GPS_lists()
|
||||
// GPS Access
|
||||
var/intgps[0] // Gps devices within the commcard -- Allow tag edits, turning on/off, etc
|
||||
var/extgps[0] // Gps devices not inside the commcard -- Print locations if a gps is on
|
||||
var/stagps[0] // Gps net status, location, whether it's on, if it's got long range
|
||||
var/obj/item/device/gps/cumulative = new(src)
|
||||
cumulative.tracking = FALSE
|
||||
cumulative.local_mode = TRUE // Won't detect long-range signals automatically
|
||||
cumulative.long_range = FALSE
|
||||
var/list/toggled_gps = list() // List of GPS units that are turned off before display_list() is called
|
||||
|
||||
for(var/obj/item/device/gps/G in internal_devices)
|
||||
var/gpsdata[0]
|
||||
if(G.tracking && !G.emped)
|
||||
cumulative.tracking = TRUE // Turn it on
|
||||
if(G.long_range)
|
||||
cumulative.long_range = TRUE // It can detect long-range
|
||||
if(!G.local_mode)
|
||||
cumulative.local_mode = FALSE // It is detecting long-range
|
||||
|
||||
gpsdata["ref"] = "\ref[G]"
|
||||
gpsdata["tag"] = G.gps_tag
|
||||
gpsdata["power"] = G.tracking
|
||||
gpsdata["local_mode"] = G.local_mode
|
||||
gpsdata["long_range"] = G.long_range
|
||||
gpsdata["hide_signal"] = G.hide_signal
|
||||
gpsdata["can_hide"] = G.can_hide_signal
|
||||
|
||||
intgps[++intgps.len] = gpsdata // Add it to the list
|
||||
|
||||
if(G.tracking)
|
||||
G.tracking = FALSE // Disable the internal gps units so they don't show up in the report
|
||||
toggled_gps += G
|
||||
|
||||
var/list/remote_gps = cumulative.display_list() // Fetch information for all units except the ones inside of this device
|
||||
|
||||
for(var/obj/item/device/gps/G in toggled_gps) // Reenable any internal GPS units
|
||||
G.tracking = TRUE
|
||||
|
||||
stagps["enabled"] = cumulative.tracking
|
||||
stagps["long_range_en"] = (cumulative.long_range && !cumulative.local_mode)
|
||||
|
||||
stagps["my_area_name"] = remote_gps["my_area_name"]
|
||||
stagps["curr_x"] = remote_gps["curr_x"]
|
||||
stagps["curr_y"] = remote_gps["curr_y"]
|
||||
stagps["curr_z"] = remote_gps["curr_z"]
|
||||
stagps["curr_z_name"] = remote_gps["curr_z_name"]
|
||||
|
||||
extgps = remote_gps["gps_list"] // Compiled by the GPS
|
||||
|
||||
qdel(cumulative) // Don't want spare GPS units building up in the contents
|
||||
|
||||
return list(
|
||||
intgps,
|
||||
extgps,
|
||||
stagps
|
||||
)
|
||||
|
||||
// Collects the current status of the supply shuttle
|
||||
// Copied from /obj/machinery/computer/supplycomp/ui_interact(),
|
||||
// code\game\machinery\computer\supply.dm, starting at line 55
|
||||
/obj/item/weapon/commcard/proc/get_supply_shuttle_status()
|
||||
var/shuttle_status[0]
|
||||
var/datum/shuttle/ferry/supply/shuttle = supply_controller.shuttle
|
||||
if(shuttle)
|
||||
if(shuttle.has_arrive_time())
|
||||
shuttle_status["location"] = "In transit"
|
||||
shuttle_status["mode"] = SUP_SHUTTLE_TRANSIT
|
||||
shuttle_status["time"] = shuttle.eta_minutes()
|
||||
|
||||
else
|
||||
shuttle_status["time"] = 0
|
||||
if(shuttle.at_station())
|
||||
if(shuttle.docking_controller)
|
||||
switch(shuttle.docking_controller.get_docking_status())
|
||||
if("docked")
|
||||
shuttle_status["location"] = "Docked"
|
||||
shuttle_status["mode"] = SUP_SHUTTLE_DOCKED
|
||||
if("undocked")
|
||||
shuttle_status["location"] = "Undocked"
|
||||
shuttle_status["mode"] = SUP_SHUTTLE_UNDOCKED
|
||||
if("docking")
|
||||
shuttle_status["location"] = "Docking"
|
||||
shuttle_status["mode"] = SUP_SHUTTLE_DOCKING
|
||||
shuttle_status["force"] = shuttle.can_force()
|
||||
if("undocking")
|
||||
shuttle_status["location"] = "Undocking"
|
||||
shuttle_status["mode"] = SUP_SHUTTLE_UNDOCKING
|
||||
shuttle_status["force"] = shuttle.can_force()
|
||||
|
||||
else
|
||||
shuttle_status["location"] = "Station"
|
||||
shuttle_status["mode"] = SUP_SHUTTLE_DOCKED
|
||||
|
||||
else
|
||||
shuttle_status["location"] = "Away"
|
||||
shuttle_status["mode"] = SUP_SHUTTLE_AWAY
|
||||
|
||||
if(shuttle.can_launch())
|
||||
shuttle_status["launch"] = 1
|
||||
else if(shuttle.can_cancel())
|
||||
shuttle_status["launch"] = 2
|
||||
else
|
||||
shuttle_status["launch"] = 0
|
||||
|
||||
switch(shuttle.moving_status)
|
||||
if(SHUTTLE_IDLE)
|
||||
shuttle_status["engine"] = "Idle"
|
||||
if(SHUTTLE_WARMUP)
|
||||
shuttle_status["engine"] = "Warming up"
|
||||
if(SHUTTLE_INTRANSIT)
|
||||
shuttle_status["engine"] = "Engaged"
|
||||
|
||||
else
|
||||
shuttle["mode"] = SUP_SHUTTLE_ERROR
|
||||
|
||||
return shuttle_status
|
||||
|
||||
// Compiles the list of supply orders
|
||||
// Copied from /obj/machinery/computer/supplycomp/ui_interact(),
|
||||
// code\game\machinery\computer\supply.dm, starting at line 130
|
||||
/obj/item/weapon/commcard/proc/get_supply_orders()
|
||||
var/orders[0]
|
||||
for(var/datum/supply_order/S in supply_controller.order_history)
|
||||
orders[++orders.len] = list(
|
||||
"ref" = "\ref[S]",
|
||||
"status" = S.status,
|
||||
"entries" = list(
|
||||
list("field" = "Supply Pack", "entry" = S.name),
|
||||
list("field" = "Cost", "entry" = S.cost),
|
||||
list("field" = "Index", "entry" = S.index),
|
||||
list("field" = "Reason", "entry" = S.comment),
|
||||
list("field" = "Ordered by", "entry" = S.ordered_by),
|
||||
list("field" = "Ordered at", "entry" = S.ordered_at),
|
||||
list("field" = "Approved by", "entry" = S.approved_by),
|
||||
list("field" = "Approved at", "entry" = S.approved_at)
|
||||
)
|
||||
)
|
||||
|
||||
return orders
|
||||
|
||||
// Compiles the list of supply export receipts
|
||||
// Copied from /obj/machinery/computer/supplycomp/ui_interact(),
|
||||
// code\game\machinery\computer\supply.dm, starting at line 147
|
||||
/obj/item/weapon/commcard/proc/get_supply_receipts()
|
||||
var/receipts[0]
|
||||
for(var/datum/exported_crate/E in supply_controller.exported_crates)
|
||||
receipts[++receipts.len] = list(
|
||||
"ref" = "\ref[E]",
|
||||
"contents" = E.contents,
|
||||
"error" = E.contents["error"],
|
||||
"title" = list(
|
||||
list("field" = "Name", "entry" = E.name),
|
||||
list("field" = "Value", "entry" = E.value)
|
||||
)
|
||||
)
|
||||
return receipts
|
||||
|
||||
|
||||
// Compiles the list of supply packs for the category currently stored in internal_data["supply_category"]
|
||||
// Copied from /obj/machinery/computer/supplycomp/ui_interact(),
|
||||
// code\game\machinery\computer\supply.dm, starting at line 147
|
||||
/obj/item/weapon/commcard/proc/get_supply_pack_list()
|
||||
var/supply_packs[0]
|
||||
for(var/pack_name in supply_controller.supply_pack)
|
||||
var/datum/supply_pack/P = supply_controller.supply_pack[pack_name]
|
||||
if(P.group == internal_data["supply_category"])
|
||||
var/list/pack = list(
|
||||
"name" = P.name,
|
||||
"cost" = P.cost,
|
||||
"contraband" = P.contraband,
|
||||
"manifest" = uniquelist(P.manifest),
|
||||
"random" = P.num_contained,
|
||||
"expand" = 0,
|
||||
"ref" = "\ref[P]"
|
||||
)
|
||||
|
||||
if(P in internal_data["supply_pack_expanded"])
|
||||
pack["expand"] = 1
|
||||
|
||||
supply_packs[++supply_packs.len] = pack
|
||||
|
||||
return supply_packs
|
||||
|
||||
|
||||
// Compiles miscellaneous data and permissions used by the supply template
|
||||
/obj/item/weapon/commcard/proc/get_misc_supply_data()
|
||||
return list(
|
||||
"shuttle_auth" = (internal_data["supply_controls"] & SUP_SEND_SHUTTLE),
|
||||
"order_auth" = (internal_data["supply_controls"] & SUP_ACCEPT_ORDERS),
|
||||
"supply_points" = supply_controller.points,
|
||||
"supply_categories" = all_supply_groups
|
||||
)
|
||||
|
||||
/obj/item/weapon/commcard/proc/get_status_display()
|
||||
return list(
|
||||
"line1" = internal_data["stat_display_line1"],
|
||||
"line2" = internal_data["stat_display_line2"],
|
||||
"active_line1" = internal_data["stat_display_active1"],
|
||||
"active_line2" = internal_data["stat_display_active2"],
|
||||
"active" = internal_data["stat_display_special"]
|
||||
)
|
||||
|
||||
/obj/item/weapon/commcard/proc/find_blast_doors()
|
||||
var/target_doors[0]
|
||||
for(var/obj/machinery/door/blast/B in machines)
|
||||
if(B.id == internal_data["shuttle_door_code"])
|
||||
target_doors += B
|
||||
|
||||
return target_doors
|
||||
@@ -68,6 +68,55 @@ var/list/GPS_list = list()
|
||||
/obj/item/device/gps/attack_self(mob/user)
|
||||
display(user)
|
||||
|
||||
// Compiles all the data not available directly from the GPS
|
||||
// Like the positions and directions to all other GPS units
|
||||
/obj/item/device/gps/proc/display_list()
|
||||
var/list/dat = list()
|
||||
|
||||
var/turf/curr = get_turf(src)
|
||||
var/area/my_area = get_area(src)
|
||||
|
||||
dat["my_area_name"] = my_area.name
|
||||
dat["curr_x"] = curr.x
|
||||
dat["curr_y"] = curr.y
|
||||
dat["curr_z"] = curr.z
|
||||
dat["curr_z_name"] = using_map.get_zlevel_name(curr.z)
|
||||
dat["gps_list"] = list()
|
||||
dat["z_level_detection"] = using_map.get_map_levels(curr.z, long_range)
|
||||
|
||||
for(var/obj/item/device/gps/G in GPS_list - src)
|
||||
if(!G.tracking || G.emped || G.hide_signal)
|
||||
continue
|
||||
|
||||
var/turf/T = get_turf(G)
|
||||
if(local_mode && curr.z != T.z)
|
||||
continue
|
||||
if(!(T.z in dat["z_level_detection"]))
|
||||
continue
|
||||
|
||||
var/gps_data[0]
|
||||
gps_data["ref"] = G
|
||||
gps_data["gps_tag"] = G.gps_tag
|
||||
|
||||
var/area/A = get_area(G)
|
||||
gps_data["area_name"] = A.name
|
||||
if(istype(A, /area/submap))
|
||||
gps_data["area_name"] = "Unknown Area" // Avoid spoilers.
|
||||
|
||||
gps_data["z_name"] = using_map.get_zlevel_name(T.z)
|
||||
gps_data["direction"] = get_adir(curr, T)
|
||||
gps_data["degrees"] = round(Get_Angle(curr,T))
|
||||
gps_data["distX"] = T.x - curr.x
|
||||
gps_data["distY"] = T.y - curr.y
|
||||
gps_data["distance"] = get_dist(curr, T)
|
||||
gps_data["local"] = (curr.z == T.z)
|
||||
gps_data["x"] = T.x
|
||||
gps_data["y"] = T.y
|
||||
|
||||
dat["gps_list"][++dat["gps_list"].len] = gps_data
|
||||
|
||||
return dat
|
||||
|
||||
/obj/item/device/gps/proc/display(mob/user)
|
||||
if(!tracking)
|
||||
to_chat(user, "The device is off. Alt-click it to turn it on.")
|
||||
@@ -77,48 +126,20 @@ var/list/GPS_list = list()
|
||||
return
|
||||
|
||||
var/list/dat = list()
|
||||
var/list/gps_data = display_list()
|
||||
|
||||
var/turf/curr = get_turf(src)
|
||||
var/area/my_area = get_area(src)
|
||||
dat += "Current location: [my_area.name] <b>([curr.x], [curr.y], [using_map.get_zlevel_name(curr.z)])</b>"
|
||||
dat += "Current location: [gps_data["my_area_name"]] <b>([gps_data["curr_x"]], [gps_data["curr_y"]], [gps_data["curr_z_name"]])</b>"
|
||||
dat += "[hide_signal ? "Tagged" : "Broadcasting"] as '[gps_tag]'. <a href='?src=\ref[src];tag=1'>\[Change Tag\]</a> \
|
||||
<a href='?src=\ref[src];range=1'>\[Toggle Scan Range\]</a> \
|
||||
[can_hide_signal ? "<a href='?src=\ref[src];hide=1'>\[Toggle Signal Visibility\]</a>":""]"
|
||||
|
||||
var/list/signals = list()
|
||||
|
||||
for(var/gps in GPS_list)
|
||||
var/obj/item/device/gps/G = gps
|
||||
if(G.emped || !G.tracking || G.hide_signal || G == src) // Their GPS isn't on or functional.
|
||||
continue
|
||||
var/turf/T = get_turf(G)
|
||||
var/z_level_detection = using_map.get_map_levels(curr.z, long_range)
|
||||
|
||||
if(local_mode && T.z != curr.z) // Only care about the current z-level.
|
||||
continue
|
||||
else if(!(T.z in z_level_detection)) // Too far away.
|
||||
continue
|
||||
|
||||
var/area/their_area = get_area(G)
|
||||
var/area_name = their_area.name
|
||||
if(istype(their_area, /area/submap))
|
||||
area_name = "Unknown Area" // Avoid spoilers.
|
||||
var/Z_name = using_map.get_zlevel_name(T.z)
|
||||
var/direction = get_adir(curr, T)
|
||||
var/distX = T.x - curr.x
|
||||
var/distY = T.y - curr.y
|
||||
var/distance = get_dist(curr, T)
|
||||
var/local = curr.z == T.z ? TRUE : FALSE
|
||||
|
||||
if(istype(gps, /obj/item/device/gps/internal/poi))
|
||||
signals += " [G.gps_tag]: [area_name] - [local ? "[direction] Dist: [round(distance, 10)]m" : "in \the [Z_name]"]"
|
||||
else
|
||||
signals += " [G.gps_tag]: [area_name], ([T.x], [T.y]) - [local ? "[direction] Dist: [distX ? "[abs(round(distX, 1))]m [(distX > 0) ? "E" : "W"], " : ""][distY ? "[abs(round(distY, 1))]m [(distY > 0) ? "N" : "S"]" : ""]" : "in \the [Z_name]"]"
|
||||
|
||||
if(signals.len)
|
||||
if(gps_data["gps_list"].len)
|
||||
dat += "Detected signals;"
|
||||
for(var/line in signals)
|
||||
dat += line
|
||||
for(var/gps in gps_data["gps_list"])
|
||||
if(istype(gps_data["ref"], /obj/item/device/gps/internal/poi))
|
||||
dat += " [gps["gps_tag"]]: [gps["area_name"]] - [gps["local"] ? "[gps["direction"]] Dist: [round(gps["distance"], 10)]m" : "in \the [gps["z_name"]]"]"
|
||||
else
|
||||
dat += " [gps["gps_tag"]]: [gps["area_name"]], ([gps["x"]], [gps["y"]]) - [gps["local"] ? "[gps["direction"]] Dist: [gps["distX"] ? "[abs(round(gps["distX"], 1))]m [(gps["distX"] > 0) ? "E" : "W"], " : ""][gps["distY"] ? "[abs(round(gps["distY"], 1))]m [(gps["distY"] > 0) ? "N" : "S"]" : ""]" : "in \the [gps["z_name"]]"]"
|
||||
else
|
||||
dat += "No other signals detected."
|
||||
|
||||
@@ -221,45 +242,17 @@ var/list/GPS_list = list()
|
||||
return
|
||||
|
||||
var/list/dat = list()
|
||||
var/list/gps_data = display_list()
|
||||
|
||||
var/turf/curr = get_turf(src)
|
||||
var/area/my_area = get_area(src)
|
||||
dat += "Current location: [my_area.name] <b>([curr.x], [curr.y], [using_map.get_zlevel_name(curr.z)])</b>"
|
||||
dat += "Current location: [gps_data["my_area_name"]] <b>([gps_data["curr_x"]], [gps_data["curr_y"]], [gps_data["curr_z_name"]])</b>"
|
||||
dat += "[hide_signal ? "Tagged" : "Broadcasting"] as '[gps_tag]'. <a href='?src=\ref[src];tag=1'>\[Change Tag\]</a> \
|
||||
<a href='?src=\ref[src];range=1'>\[Toggle Scan Range\]</a> \
|
||||
[can_hide_signal ? "<a href='?src=\ref[src];hide=1'>\[Toggle Signal Visibility\]</a>":""]"
|
||||
|
||||
var/list/signals = list()
|
||||
|
||||
for(var/gps in GPS_list)
|
||||
var/obj/item/device/gps/G = gps
|
||||
if(G.emped || !G.tracking || G.hide_signal || G == src) // Their GPS isn't on or functional.
|
||||
continue
|
||||
var/turf/T = get_turf(G)
|
||||
var/z_level_detection = using_map.get_map_levels(curr.z, long_range)
|
||||
|
||||
if(local_mode && T.z != curr.z) // Only care about the current z-level.
|
||||
continue
|
||||
else if(!(T.z in z_level_detection)) // Too far away.
|
||||
continue
|
||||
|
||||
var/area/their_area = get_area(G)
|
||||
var/area_name = their_area.name
|
||||
if(istype(their_area, /area/submap))
|
||||
area_name = "Unknown Area" // Avoid spoilers.
|
||||
var/Z_name = using_map.get_zlevel_name(T.z)
|
||||
var/coord = "[T.x], [T.y], [Z_name]"
|
||||
var/degrees = round(Get_Angle(curr, T))
|
||||
var/direction = get_adir(curr, T)
|
||||
var/distance = get_dist(curr, T)
|
||||
var/local = curr.z == T.z ? TRUE : FALSE
|
||||
|
||||
signals += " [G.gps_tag]: [area_name] ([coord]) [local ? "Dist: [distance]m Dir: [degrees]° ([direction])":""]"
|
||||
|
||||
if(signals.len)
|
||||
if(gps_data["gps_list"].len)
|
||||
dat += "Detected signals;"
|
||||
for(var/line in signals)
|
||||
dat += line
|
||||
for(var/gps in gps_data["gps_list"])
|
||||
dat += " [gps["gps_tag"]]: [gps["area_name"]] ([gps["x"]], [gps["y"]], [gps["z_name"]]) [gps["local"] ? "Dist: [gps["distance"]]m Dir: [gps["degrees"]]° ([gps["direction"]])" :""]"
|
||||
else
|
||||
dat += "No other signals detected."
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
|
||||
if(hack_result && in_hack_mode)
|
||||
user << "<span class='notice'>Your hacking attempt was succesful!</span>"
|
||||
user.playsound_local(get_turf(src), 'sound/piano/A#6.ogg', 50)
|
||||
user.playsound_local(get_turf(src), 'sound/instruments/piano/An6.ogg', 50)
|
||||
else
|
||||
user << "<span class='warning'>Your hacking attempt failed!</span>"
|
||||
return 0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/obj/item/device/text_to_speech
|
||||
name = "TTS device"
|
||||
desc = "A device that speaks an inputted message. Given to crew which can not speak properly or at all."
|
||||
icon = 'icons/obj/electronic_assemblies.dmi'
|
||||
icon = 'icons/obj/integrated_electronics/electronic_setups.dmi'
|
||||
icon_state = "setup_small"
|
||||
w_class = ITEMSIZE_SMALL
|
||||
var/named
|
||||
|
||||
@@ -1,392 +1,41 @@
|
||||
//copy pasta of the space piano, don't hurt me -Pete
|
||||
|
||||
/obj/item/device/violin
|
||||
name = "space violin"
|
||||
desc = "A wooden musical instrument with four strings and a bow. \"The devil went down to space, he was looking for an assistant to grief.\""
|
||||
/obj/item/device/instrument
|
||||
name = "generic instrument"
|
||||
var/datum/song/handheld/song
|
||||
var/instrumentId = "generic"
|
||||
var/instrumentExt = "mid"
|
||||
icon = 'icons/obj/musician.dmi'
|
||||
icon_state = "violin"
|
||||
force = 10
|
||||
var/datum/song/song
|
||||
var/playing = 0
|
||||
var/help = 0
|
||||
var/edit = 1
|
||||
var/repeat = 0
|
||||
|
||||
/obj/item/device/violin/proc/playnote(var/note as text)
|
||||
//world << "Note: [note]"
|
||||
var/soundfile
|
||||
/*BYOND loads resource files at compile time if they are ''. This means you can't really manipulate them dynamically.
|
||||
Tried doing it dynamically at first but its more trouble than its worth. Would have saved many lines tho.*/
|
||||
switch(note)
|
||||
if("Cn1") soundfile = 'sound/violin/Cn1.mid'
|
||||
if("C#1") soundfile = 'sound/violin/C#1.mid'
|
||||
if("Db1") soundfile = 'sound/violin/Db1.mid'
|
||||
if("Dn1") soundfile = 'sound/violin/Dn1.mid'
|
||||
if("D#1") soundfile = 'sound/violin/D#1.mid'
|
||||
if("Eb1") soundfile = 'sound/violin/Eb1.mid'
|
||||
if("En1") soundfile = 'sound/violin/En1.mid'
|
||||
if("E#1") soundfile = 'sound/violin/E#1.mid'
|
||||
if("Fb1") soundfile = 'sound/violin/Fb1.mid'
|
||||
if("Fn1") soundfile = 'sound/violin/Fn1.mid'
|
||||
if("F#1") soundfile = 'sound/violin/F#1.mid'
|
||||
if("Gb1") soundfile = 'sound/violin/Gb1.mid'
|
||||
if("Gn1") soundfile = 'sound/violin/Gn1.mid'
|
||||
if("G#1") soundfile = 'sound/violin/G#1.mid'
|
||||
if("Ab1") soundfile = 'sound/violin/Ab1.mid'
|
||||
if("An1") soundfile = 'sound/violin/An1.mid'
|
||||
if("A#1") soundfile = 'sound/violin/A#1.mid'
|
||||
if("Bb1") soundfile = 'sound/violin/Bb1.mid'
|
||||
if("Bn1") soundfile = 'sound/violin/Bn1.mid'
|
||||
if("B#1") soundfile = 'sound/violin/B#1.mid'
|
||||
if("Cb2") soundfile = 'sound/violin/Cb2.mid'
|
||||
if("Cn2") soundfile = 'sound/violin/Cn2.mid'
|
||||
if("C#2") soundfile = 'sound/violin/C#2.mid'
|
||||
if("Db2") soundfile = 'sound/violin/Db2.mid'
|
||||
if("Dn2") soundfile = 'sound/violin/Dn2.mid'
|
||||
if("D#2") soundfile = 'sound/violin/D#2.mid'
|
||||
if("Eb2") soundfile = 'sound/violin/Eb2.mid'
|
||||
if("En2") soundfile = 'sound/violin/En2.mid'
|
||||
if("E#2") soundfile = 'sound/violin/E#2.mid'
|
||||
if("Fb2") soundfile = 'sound/violin/Fb2.mid'
|
||||
if("Fn2") soundfile = 'sound/violin/Fn2.mid'
|
||||
if("F#2") soundfile = 'sound/violin/F#2.mid'
|
||||
if("Gb2") soundfile = 'sound/violin/Gb2.mid'
|
||||
if("Gn2") soundfile = 'sound/violin/Gn2.mid'
|
||||
if("G#2") soundfile = 'sound/violin/G#2.mid'
|
||||
if("Ab2") soundfile = 'sound/violin/Ab2.mid'
|
||||
if("An2") soundfile = 'sound/violin/An2.mid'
|
||||
if("A#2") soundfile = 'sound/violin/A#2.mid'
|
||||
if("Bb2") soundfile = 'sound/violin/Bb2.mid'
|
||||
if("Bn2") soundfile = 'sound/violin/Bn2.mid'
|
||||
if("B#2") soundfile = 'sound/violin/B#2.mid'
|
||||
if("Cb3") soundfile = 'sound/violin/Cb3.mid'
|
||||
if("Cn3") soundfile = 'sound/violin/Cn3.mid'
|
||||
if("C#3") soundfile = 'sound/violin/C#3.mid'
|
||||
if("Db3") soundfile = 'sound/violin/Db3.mid'
|
||||
if("Dn3") soundfile = 'sound/violin/Dn3.mid'
|
||||
if("D#3") soundfile = 'sound/violin/D#3.mid'
|
||||
if("Eb3") soundfile = 'sound/violin/Eb3.mid'
|
||||
if("En3") soundfile = 'sound/violin/En3.mid'
|
||||
if("E#3") soundfile = 'sound/violin/E#3.mid'
|
||||
if("Fb3") soundfile = 'sound/violin/Fb3.mid'
|
||||
if("Fn3") soundfile = 'sound/violin/Fn3.mid'
|
||||
if("F#3") soundfile = 'sound/violin/F#3.mid'
|
||||
if("Gb3") soundfile = 'sound/violin/Gb3.mid'
|
||||
if("Gn3") soundfile = 'sound/violin/Gn3.mid'
|
||||
if("G#3") soundfile = 'sound/violin/G#3.mid'
|
||||
if("Ab3") soundfile = 'sound/violin/Ab3.mid'
|
||||
if("An3") soundfile = 'sound/violin/An3.mid'
|
||||
if("A#3") soundfile = 'sound/violin/A#3.mid'
|
||||
if("Bb3") soundfile = 'sound/violin/Bb3.mid'
|
||||
if("Bn3") soundfile = 'sound/violin/Bn3.mid'
|
||||
if("B#3") soundfile = 'sound/violin/B#3.mid'
|
||||
if("Cb4") soundfile = 'sound/violin/Cb4.mid'
|
||||
if("Cn4") soundfile = 'sound/violin/Cn4.mid'
|
||||
if("C#4") soundfile = 'sound/violin/C#4.mid'
|
||||
if("Db4") soundfile = 'sound/violin/Db4.mid'
|
||||
if("Dn4") soundfile = 'sound/violin/Dn4.mid'
|
||||
if("D#4") soundfile = 'sound/violin/D#4.mid'
|
||||
if("Eb4") soundfile = 'sound/violin/Eb4.mid'
|
||||
if("En4") soundfile = 'sound/violin/En4.mid'
|
||||
if("E#4") soundfile = 'sound/violin/E#4.mid'
|
||||
if("Fb4") soundfile = 'sound/violin/Fb4.mid'
|
||||
if("Fn4") soundfile = 'sound/violin/Fn4.mid'
|
||||
if("F#4") soundfile = 'sound/violin/F#4.mid'
|
||||
if("Gb4") soundfile = 'sound/violin/Gb4.mid'
|
||||
if("Gn4") soundfile = 'sound/violin/Gn4.mid'
|
||||
if("G#4") soundfile = 'sound/violin/G#4.mid'
|
||||
if("Ab4") soundfile = 'sound/violin/Ab4.mid'
|
||||
if("An4") soundfile = 'sound/violin/An4.mid'
|
||||
if("A#4") soundfile = 'sound/violin/A#4.mid'
|
||||
if("Bb4") soundfile = 'sound/violin/Bb4.mid'
|
||||
if("Bn4") soundfile = 'sound/violin/Bn4.mid'
|
||||
if("B#4") soundfile = 'sound/violin/B#4.mid'
|
||||
if("Cb5") soundfile = 'sound/violin/Cb5.mid'
|
||||
if("Cn5") soundfile = 'sound/violin/Cn5.mid'
|
||||
if("C#5") soundfile = 'sound/violin/C#5.mid'
|
||||
if("Db5") soundfile = 'sound/violin/Db5.mid'
|
||||
if("Dn5") soundfile = 'sound/violin/Dn5.mid'
|
||||
if("D#5") soundfile = 'sound/violin/D#5.mid'
|
||||
if("Eb5") soundfile = 'sound/violin/Eb5.mid'
|
||||
if("En5") soundfile = 'sound/violin/En5.mid'
|
||||
if("E#5") soundfile = 'sound/violin/E#5.mid'
|
||||
if("Fb5") soundfile = 'sound/violin/Fb5.mid'
|
||||
if("Fn5") soundfile = 'sound/violin/Fn5.mid'
|
||||
if("F#5") soundfile = 'sound/violin/F#5.mid'
|
||||
if("Gb5") soundfile = 'sound/violin/Gb5.mid'
|
||||
if("Gn5") soundfile = 'sound/violin/Gn5.mid'
|
||||
if("G#5") soundfile = 'sound/violin/G#5.mid'
|
||||
if("Ab5") soundfile = 'sound/violin/Ab5.mid'
|
||||
if("An5") soundfile = 'sound/violin/An5.mid'
|
||||
if("A#5") soundfile = 'sound/violin/A#5.mid'
|
||||
if("Bb5") soundfile = 'sound/violin/Bb5.mid'
|
||||
if("Bn5") soundfile = 'sound/violin/Bn5.mid'
|
||||
if("B#5") soundfile = 'sound/violin/B#5.mid'
|
||||
if("Cb6") soundfile = 'sound/violin/Cb6.mid'
|
||||
if("Cn6") soundfile = 'sound/violin/Cn6.mid'
|
||||
if("C#6") soundfile = 'sound/violin/C#6.mid'
|
||||
if("Db6") soundfile = 'sound/violin/Db6.mid'
|
||||
if("Dn6") soundfile = 'sound/violin/Dn6.mid'
|
||||
if("D#6") soundfile = 'sound/violin/D#6.mid'
|
||||
if("Eb6") soundfile = 'sound/violin/Eb6.mid'
|
||||
if("En6") soundfile = 'sound/violin/En6.mid'
|
||||
if("E#6") soundfile = 'sound/violin/E#6.mid'
|
||||
if("Fb6") soundfile = 'sound/violin/Fb6.mid'
|
||||
if("Fn6") soundfile = 'sound/violin/Fn6.mid'
|
||||
if("F#6") soundfile = 'sound/violin/F#6.mid'
|
||||
if("Gb6") soundfile = 'sound/violin/Gb6.mid'
|
||||
if("Gn6") soundfile = 'sound/violin/Gn6.mid'
|
||||
if("G#6") soundfile = 'sound/violin/G#6.mid'
|
||||
if("Ab6") soundfile = 'sound/violin/Ab6.mid'
|
||||
if("An6") soundfile = 'sound/violin/An6.mid'
|
||||
if("A#6") soundfile = 'sound/violin/A#6.mid'
|
||||
if("Bb6") soundfile = 'sound/violin/Bb6.mid'
|
||||
if("Bn6") soundfile = 'sound/violin/Bn6.mid'
|
||||
if("B#6") soundfile = 'sound/violin/B#6.mid'
|
||||
if("Cb7") soundfile = 'sound/violin/Cb7.mid'
|
||||
if("Cn7") soundfile = 'sound/violin/Cn7.mid'
|
||||
if("C#7") soundfile = 'sound/violin/C#7.mid'
|
||||
if("Db7") soundfile = 'sound/violin/Db7.mid'
|
||||
if("Dn7") soundfile = 'sound/violin/Dn7.mid'
|
||||
if("D#7") soundfile = 'sound/violin/D#7.mid'
|
||||
if("Eb7") soundfile = 'sound/violin/Eb7.mid'
|
||||
if("En7") soundfile = 'sound/violin/En7.mid'
|
||||
if("E#7") soundfile = 'sound/violin/E#7.mid'
|
||||
if("Fb7") soundfile = 'sound/violin/Fb7.mid'
|
||||
if("Fn7") soundfile = 'sound/violin/Fn7.mid'
|
||||
if("F#7") soundfile = 'sound/violin/F#7.mid'
|
||||
if("Gb7") soundfile = 'sound/violin/Gb7.mid'
|
||||
if("Gn7") soundfile = 'sound/violin/Gn7.mid'
|
||||
if("G#7") soundfile = 'sound/violin/G#7.mid'
|
||||
if("Ab7") soundfile = 'sound/violin/Ab7.mid'
|
||||
if("An7") soundfile = 'sound/violin/An7.mid'
|
||||
if("A#7") soundfile = 'sound/violin/A#7.mid'
|
||||
if("Bb7") soundfile = 'sound/violin/Bb7.mid'
|
||||
if("Bn7") soundfile = 'sound/violin/Bn7.mid'
|
||||
if("B#7") soundfile = 'sound/violin/B#7.mid'
|
||||
if("Cb8") soundfile = 'sound/violin/Cb8.mid'
|
||||
if("Cn8") soundfile = 'sound/violin/Cn8.mid'
|
||||
if("C#8") soundfile = 'sound/violin/C#8.mid'
|
||||
if("Db8") soundfile = 'sound/violin/Db8.mid'
|
||||
if("Dn8") soundfile = 'sound/violin/Dn8.mid'
|
||||
if("D#8") soundfile = 'sound/violin/D#8.mid'
|
||||
if("Eb8") soundfile = 'sound/violin/Eb8.mid'
|
||||
if("En8") soundfile = 'sound/violin/En8.mid'
|
||||
if("E#8") soundfile = 'sound/violin/E#8.mid'
|
||||
if("Fb8") soundfile = 'sound/violin/Fb8.mid'
|
||||
if("Fn8") soundfile = 'sound/violin/Fn8.mid'
|
||||
if("F#8") soundfile = 'sound/violin/F#8.mid'
|
||||
if("Gb8") soundfile = 'sound/violin/Gb8.mid'
|
||||
if("Gn8") soundfile = 'sound/violin/Gn8.mid'
|
||||
if("G#8") soundfile = 'sound/violin/G#8.mid'
|
||||
if("Ab8") soundfile = 'sound/violin/Ab8.mid'
|
||||
if("An8") soundfile = 'sound/violin/An8.mid'
|
||||
if("A#8") soundfile = 'sound/violin/A#8.mid'
|
||||
if("Bb8") soundfile = 'sound/violin/Bb8.mid'
|
||||
if("Bn8") soundfile = 'sound/violin/Bn8.mid'
|
||||
if("B#8") soundfile = 'sound/violin/B#8.mid'
|
||||
if("Cb9") soundfile = 'sound/violin/Cb9.mid'
|
||||
if("Cn9") soundfile = 'sound/violin/Cn9.mid'
|
||||
else return
|
||||
/obj/item/device/instrument/New()
|
||||
..()
|
||||
song = new(instrumentId, src)
|
||||
song.instrumentExt = instrumentExt
|
||||
|
||||
hearers(15, get_turf(src)) << sound(soundfile)
|
||||
/obj/item/device/instrument/Destroy()
|
||||
qdel(song)
|
||||
song = null
|
||||
..()
|
||||
|
||||
/obj/item/device/violin/proc/playsong()
|
||||
do
|
||||
var/cur_oct[7]
|
||||
var/cur_acc[7]
|
||||
for(var/i = 1 to 7)
|
||||
cur_oct[i] = "3"
|
||||
cur_acc[i] = "n"
|
||||
/obj/item/device/instrument/attack_self(mob/user as mob)
|
||||
if(!user.IsAdvancedToolUser())
|
||||
to_chat(user, "<span class='warning'>You don't have the dexterity to do this!</span>")
|
||||
return 1
|
||||
interact(user)
|
||||
|
||||
for(var/line in song.lines)
|
||||
//world << line
|
||||
for(var/beat in splittext(lowertext(line), ","))
|
||||
//world << "beat: [beat]"
|
||||
var/list/notes = splittext(beat, "/")
|
||||
for(var/note in splittext(notes[1], "-"))
|
||||
//world << "note: [note]"
|
||||
if(!playing || !isliving(loc))//If the violin is playing, or isn't held by a person
|
||||
playing = 0
|
||||
return
|
||||
if(lentext(note) == 0)
|
||||
continue
|
||||
//world << "Parse: [copytext(note,1,2)]"
|
||||
var/cur_note = text2ascii(note) - 96
|
||||
if(cur_note < 1 || cur_note > 7)
|
||||
continue
|
||||
for(var/i=2 to lentext(note))
|
||||
var/ni = copytext(note,i,i+1)
|
||||
if(!text2num(ni))
|
||||
if(ni == "#" || ni == "b" || ni == "n")
|
||||
cur_acc[cur_note] = ni
|
||||
else if(ni == "s")
|
||||
cur_acc[cur_note] = "#" // so shift is never required
|
||||
else
|
||||
cur_oct[cur_note] = ni
|
||||
playnote(uppertext(copytext(note,1,2)) + cur_acc[cur_note] + cur_oct[cur_note])
|
||||
if(notes.len >= 2 && text2num(notes[2]))
|
||||
sleep(song.tempo / text2num(notes[2]))
|
||||
else
|
||||
sleep(song.tempo)
|
||||
if(repeat > 0)
|
||||
repeat-- //Infinite loops are baaaad.
|
||||
while(repeat > 0)
|
||||
playing = 0
|
||||
|
||||
/obj/item/device/violin/attack_self(mob/user as mob)
|
||||
if(!isliving(user) || user.stat || user.restrained() || user.lying) return
|
||||
user.set_machine(src)
|
||||
|
||||
var/dat = "<HEAD><TITLE>Violin</TITLE></HEAD><BODY>"
|
||||
|
||||
if(song)
|
||||
if(song.lines.len > 0 && !(playing))
|
||||
dat += "<A href='?src=\ref[src];play=1'>Play Song</A><BR><BR>"
|
||||
dat += "<A href='?src=\ref[src];repeat=1'>Repeat Song: [repeat] times.</A><BR><BR>"
|
||||
if(playing)
|
||||
dat += "<A href='?src=\ref[src];stop=1'>Stop Playing</A><BR>"
|
||||
dat += "Repeats left: [repeat].<BR><BR>"
|
||||
if(!edit)
|
||||
dat += "<A href='?src=\ref[src];edit=2'>Show Editor</A><BR><BR>"
|
||||
else
|
||||
dat += "<A href='?src=\ref[src];edit=1'>Hide Editor</A><BR>"
|
||||
dat += "<A href='?src=\ref[src];newsong=1'>Start a New Song</A><BR>"
|
||||
dat += "<A href='?src=\ref[src];import=1'>Import a Song</A><BR><BR>"
|
||||
if(song)
|
||||
var/calctempo = (10/song.tempo)*60
|
||||
dat += "Tempo : <A href='?src=\ref[src];tempo=10'>-</A><A href='?src=\ref[src];tempo=1'>-</A> [calctempo] BPM <A href='?src=\ref[src];tempo=-1'>+</A><A href='?src=\ref[src];tempo=-10'>+</A><BR><BR>"
|
||||
var/linecount = 0
|
||||
for(var/line in song.lines)
|
||||
linecount += 1
|
||||
dat += "Line [linecount]: [line] <A href='?src=\ref[src];deleteline=[linecount]'>Delete Line</A> <A href='?src=\ref[src];modifyline=[linecount]'>Modify Line</A><BR>"
|
||||
dat += "<A href='?src=\ref[src];newline=1'>Add Line</A><BR><BR>"
|
||||
if(help)
|
||||
dat += "<A href='?src=\ref[src];help=1'>Hide Help</A><BR>"
|
||||
dat += {"
|
||||
Lines are a series of chords, separated by commas (,), each with notes seperated by hyphens (-).<br>
|
||||
Every note in a chord will play together, with chord timed by the tempo.<br>
|
||||
<br>
|
||||
Notes are played by the names of the note, and optionally, the accidental, and/or the octave number.<br>
|
||||
By default, every note is natural and in octave 3. Defining otherwise is remembered for each note.<br>
|
||||
Example: <i>C,D,E,F,G,A,B</i> will play a C major scale.<br>
|
||||
After a note has an accidental placed, it will be remembered: <i>C,C4,C,C3</i> is <i>C3,C4,C4,C3</i><br>
|
||||
Chords can be played simply by seperating each note with a hyphon: <i>A-C#,Cn-E,E-G#,Gn-B</i><br>
|
||||
A pause may be denoted by an empty chord: <i>C,E,,C,G</i><br>
|
||||
To make a chord be a different time, end it with /x, where the chord length will be length<br>
|
||||
defined by tempo / x: <i>C,G/2,E/4</i><br>
|
||||
Combined, an example is: <i>E-E4/4,/2,G#/8,B/8,E3-E4/4</i>
|
||||
<br>
|
||||
Lines may be up to 50 characters.<br>
|
||||
A song may only contain up to 50 lines.<br>
|
||||
"}
|
||||
else
|
||||
dat += "<A href='?src=\ref[src];help=2'>Show Help</A><BR>"
|
||||
dat += "</BODY></HTML>"
|
||||
user << browse(dat, "window=violin;size=700x300")
|
||||
onclose(user, "violin")
|
||||
|
||||
/obj/item/device/violin/Topic(href, href_list)
|
||||
|
||||
if(!in_range(src, usr) || issilicon(usr) || !isliving(usr) || !usr.canmove || usr.restrained())
|
||||
usr << browse(null, "window=violin;size=700x300")
|
||||
onclose(usr, "violin")
|
||||
/obj/item/device/instrument/interact(mob/user as mob)
|
||||
if(!user)
|
||||
return
|
||||
|
||||
if(href_list["newsong"])
|
||||
song = new()
|
||||
else if(song)
|
||||
if(href_list["repeat"]) //Changing this from a toggle to a number of repeats to avoid infinite loops.
|
||||
if(playing) return //So that people cant keep adding to repeat. If the do it intentionally, it could result in the server crashing.
|
||||
var/tempnum = input("How many times do you want to repeat this piece? (max:10)") as num|null
|
||||
if(tempnum > 10)
|
||||
tempnum = 10
|
||||
if(tempnum < 0)
|
||||
tempnum = 0
|
||||
repeat = round(tempnum)
|
||||
if(user.incapacitated() || user.lying)
|
||||
return
|
||||
|
||||
else if(href_list["tempo"])
|
||||
song.tempo += round(text2num(href_list["tempo"]))
|
||||
if(song.tempo < 1)
|
||||
song.tempo = 1
|
||||
user.set_machine(src)
|
||||
song.interact(user)
|
||||
|
||||
else if(href_list["play"])
|
||||
if(song)
|
||||
playing = 1
|
||||
spawn() playsong()
|
||||
|
||||
else if(href_list["newline"])
|
||||
var/newline = html_encode(input("Enter your line: ", "violin") as text|null)
|
||||
if(!newline)
|
||||
return
|
||||
if(song.lines.len > 50)
|
||||
return
|
||||
if(lentext(newline) > 50)
|
||||
newline = copytext(newline, 1, 50)
|
||||
song.lines.Add(newline)
|
||||
|
||||
else if(href_list["deleteline"])
|
||||
var/num = round(text2num(href_list["deleteline"]))
|
||||
if(num > song.lines.len || num < 1)
|
||||
return
|
||||
song.lines.Cut(num, num+1)
|
||||
|
||||
else if(href_list["modifyline"])
|
||||
var/num = round(text2num(href_list["modifyline"]),1)
|
||||
var/content = html_encode(input("Enter your line: ", "violin", song.lines[num]) as text|null)
|
||||
if(!content)
|
||||
return
|
||||
if(lentext(content) > 50)
|
||||
content = copytext(content, 1, 50)
|
||||
if(num > song.lines.len || num < 1)
|
||||
return
|
||||
song.lines[num] = content
|
||||
|
||||
else if(href_list["stop"])
|
||||
playing = 0
|
||||
|
||||
else if(href_list["help"])
|
||||
help = text2num(href_list["help"]) - 1
|
||||
|
||||
else if(href_list["edit"])
|
||||
edit = text2num(href_list["edit"]) - 1
|
||||
|
||||
else if(href_list["import"])
|
||||
var/t = ""
|
||||
do
|
||||
t = html_encode(input(usr, "Please paste the entire song, formatted:", text("[]", name), t) as message)
|
||||
if(!in_range(src, usr))
|
||||
return
|
||||
|
||||
if(lentext(t) >= 3072)
|
||||
var/cont = input(usr, "Your message is too long! Would you like to continue editing it?", "", "yes") in list("yes", "no")
|
||||
if(cont == "no")
|
||||
break
|
||||
while(lentext(t) > 3072)
|
||||
|
||||
//split into lines
|
||||
spawn()
|
||||
var/list/lines = splittext(t, "\n")
|
||||
var/tempo = 5
|
||||
if(copytext(lines[1],1,6) == "BPM: ")
|
||||
tempo = 600 / text2num(copytext(lines[1],6))
|
||||
lines.Cut(1,2)
|
||||
if(lines.len > 50)
|
||||
usr << "Too many lines!"
|
||||
lines.Cut(51)
|
||||
var/linenum = 1
|
||||
for(var/l in lines)
|
||||
if(lentext(l) > 50)
|
||||
usr << "Line [linenum] too long!"
|
||||
lines.Remove(l)
|
||||
else
|
||||
linenum++
|
||||
song = new()
|
||||
song.lines = lines
|
||||
song.tempo = tempo
|
||||
|
||||
add_fingerprint(usr)
|
||||
for(var/mob/M in viewers(1, loc))
|
||||
if((M.client && M.machine == src))
|
||||
attack_self(M)
|
||||
return
|
||||
/obj/item/device/instrument/violin
|
||||
name = "space violin"
|
||||
desc = "A wooden musical instrument with four strings and a bow. \"The devil went down to space, he was looking for an assistant to grief.\""
|
||||
icon_state = "violin"
|
||||
attack_verb = list("smashed")
|
||||
instrumentId = "violin"
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
name = "SCP"
|
||||
|
||||
/obj/structure/largecrate/animal/crashedshuttle/initialize()
|
||||
starts_with = pick(/mob/living/simple_animal/hostile/statue, /obj/item/cursed_marble, /obj/item/weapon/deadringer)
|
||||
starts_with = list(pick(/mob/living/simple_animal/hostile/statue, /obj/item/cursed_marble, /obj/item/weapon/deadringer)) // Starts_with has to be a list
|
||||
name = pick("Spicy Crust Pizzeria", "Soap and Care Products", "Sally's Computer Parts", "Steve's Chocolate Pastries", "Smith & Christian's Plastics","Standard Containers & Packaging Co.", "Sanitary Chemical Purgation (LTD)")
|
||||
name += " delivery crate"
|
||||
return ..()
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
/obj/item/weapon/reagent_containers/food/snacks/grown/ambrosiadeus,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/grown/ambrosiavulgaris,
|
||||
/obj/item/device/paicard,
|
||||
/obj/item/device/violin,
|
||||
/obj/item/device/instrument/violin,
|
||||
/obj/item/weapon/storage/belt/utility/full,
|
||||
/obj/item/clothing/accessory/tie/horrible)
|
||||
|
||||
|
||||
@@ -38,23 +38,8 @@
|
||||
fragment_types = list(/obj/item/projectile/bullet/pellet/fragment)
|
||||
num_fragments = 200 //total number of fragments produced by the grenade
|
||||
|
||||
/obj/item/weapon/grenade/explosive/mini
|
||||
name = "mini fragmentation grenade"
|
||||
desc = "A miniaturized fragmentation grenade, this one poses relatively little threat on its own."
|
||||
icon_state = "minifrag"
|
||||
fragment_types = list(/obj/item/projectile/bullet/pellet/fragment/weak, /obj/item/projectile/bullet/pellet/fragment/weak, /obj/item/projectile/bullet/pellet/fragment, /obj/item/projectile/bullet/pellet/fragment/strong)
|
||||
num_fragments = 20
|
||||
spread_range = 3
|
||||
explosion_size = 1
|
||||
|
||||
// This thing literally just explodes
|
||||
/obj/item/weapon/grenade/explosive/concussion
|
||||
name = "concussion grenade"
|
||||
desc = "A small explosive grenade"
|
||||
num_fragments = 0
|
||||
|
||||
|
||||
// This proc is only here because I don't know where else to put it, should be kept at the bottom of this file unless moved to a more appropriate location
|
||||
/obj/proc/fragmentate(var/turf/T=get_turf(src), var/fragment_number = 30, var/spreading_range = 5, var/list/fragtypes=list(/obj/item/projectile/bullet/pellet/fragment/))
|
||||
set waitfor = 0
|
||||
var/list/target_turfs = getcircle(T, spreading_range)
|
||||
@@ -79,3 +64,12 @@
|
||||
P.attack_mob(M, 0, 25) //you're holding a grenade, dude!
|
||||
else
|
||||
P.attack_mob(M, 0, 100) //otherwise, allow a decent amount of fragments to pass
|
||||
|
||||
/obj/item/weapon/grenade/explosive/mini
|
||||
name = "mini fragmentation grenade"
|
||||
desc = "A miniaturized fragmentation grenade, this one poses relatively little threat on its own."
|
||||
icon_state = "minifrag"
|
||||
fragment_types = list(/obj/item/projectile/bullet/pellet/fragment/weak, /obj/item/projectile/bullet/pellet/fragment/weak, /obj/item/projectile/bullet/pellet/fragment, /obj/item/projectile/bullet/pellet/fragment/strong)
|
||||
num_fragments = 20
|
||||
spread_range = 3
|
||||
explosion_size = 1
|
||||
|
||||
@@ -99,6 +99,9 @@
|
||||
cuffs.loc = target
|
||||
target.handcuffed = cuffs
|
||||
target.update_inv_handcuffed()
|
||||
target.drop_r_hand()
|
||||
target.drop_l_hand()
|
||||
target.stop_pulling()
|
||||
return 1
|
||||
|
||||
/obj/item/weapon/handcuffs/equipped(var/mob/living/user,var/slot)
|
||||
@@ -212,50 +215,12 @@ var/last_chew = 0
|
||||
elastic = 0
|
||||
cuff_sound = 'sound/weapons/handcuffs.ogg' //This shold work for now.
|
||||
|
||||
/obj/item/weapon/handcuffs/legcuffs/bola
|
||||
name = "bola"
|
||||
desc = "Keeps prey in line."
|
||||
elastic = 1
|
||||
use_time = 0
|
||||
breakouttime = 30
|
||||
cuff_sound = 'sound/weapons/towelwipe.ogg' //Is there anything this sound can't do?
|
||||
|
||||
/obj/item/weapon/handcuffs/legcuffs/get_worn_icon_state(var/slot_name)
|
||||
if(slot_name == slot_legcuffed_str)
|
||||
return "legcuff1"
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/handcuffs/legcuffs/bola/can_place(var/mob/target, var/mob/user)
|
||||
if(user) //A ranged legcuff, until proper implementation as items it remains a projectile-only thing.
|
||||
return 1
|
||||
|
||||
/obj/item/weapon/handcuffs/legcuffs/bola/dropped()
|
||||
visible_message("<span class='notice'>\The [src] falls apart!</span>")
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/handcuffs/legcuffs/bola/place_legcuffs(var/mob/living/carbon/target, var/mob/user)
|
||||
playsound(src.loc, cuff_sound, 30, 1, -2)
|
||||
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(!istype(H))
|
||||
src.dropped()
|
||||
return 0
|
||||
|
||||
if(!H.has_organ_for_slot(slot_legcuffed))
|
||||
H.visible_message("<span class='notice'>\The [src] slams into [H], but slides off!</span>")
|
||||
src.dropped()
|
||||
return 0
|
||||
|
||||
H.visible_message("<span class='danger'>\The [H] has been snared by \the [src]!</span>")
|
||||
|
||||
// Apply cuffs.
|
||||
var/obj/item/weapon/handcuffs/legcuffs/lcuffs = src
|
||||
lcuffs.loc = target
|
||||
target.legcuffed = lcuffs
|
||||
target.update_inv_legcuffed()
|
||||
return 1
|
||||
|
||||
/obj/item/weapon/handcuffs/legcuffs/attack(var/mob/living/carbon/C, var/mob/living/user)
|
||||
if(!user.IsAdvancedToolUser())
|
||||
return
|
||||
@@ -316,6 +281,10 @@ var/last_chew = 0
|
||||
lcuffs.loc = target
|
||||
target.legcuffed = lcuffs
|
||||
target.update_inv_legcuffed()
|
||||
if(target.m_intent != "walk")
|
||||
target.m_intent = "walk"
|
||||
if(target.hud_used && user.hud_used.move_intent)
|
||||
target.hud_used.move_intent.icon_state = "walking"
|
||||
return 1
|
||||
|
||||
/obj/item/weapon/handcuffs/legcuffs/equipped(var/mob/living/user,var/slot)
|
||||
@@ -325,3 +294,46 @@ var/last_chew = 0
|
||||
user.m_intent = "walk"
|
||||
if(user.hud_used && user.hud_used.move_intent)
|
||||
user.hud_used.move_intent.icon_state = "walking"
|
||||
|
||||
|
||||
/obj/item/weapon/handcuffs/legcuffs/bola
|
||||
name = "bola"
|
||||
desc = "Keeps prey in line."
|
||||
elastic = 1
|
||||
use_time = 0
|
||||
breakouttime = 30
|
||||
cuff_sound = 'sound/weapons/towelwipe.ogg' //Is there anything this sound can't do?
|
||||
|
||||
/obj/item/weapon/handcuffs/legcuffs/bola/can_place(var/mob/target, var/mob/user)
|
||||
if(user) //A ranged legcuff, until proper implementation as items it remains a projectile-only thing.
|
||||
return 1
|
||||
|
||||
/obj/item/weapon/handcuffs/legcuffs/bola/dropped()
|
||||
visible_message("<span class='notice'>\The [src] falls apart!</span>")
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/handcuffs/legcuffs/bola/place_legcuffs(var/mob/living/carbon/target, var/mob/user)
|
||||
playsound(src.loc, cuff_sound, 30, 1, -2)
|
||||
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(!istype(H))
|
||||
src.dropped()
|
||||
return 0
|
||||
|
||||
if(!H.has_organ_for_slot(slot_legcuffed))
|
||||
H.visible_message("<span class='notice'>\The [src] slams into [H], but slides off!</span>")
|
||||
src.dropped()
|
||||
return 0
|
||||
|
||||
H.visible_message("<span class='danger'>\The [H] has been snared by \the [src]!</span>")
|
||||
|
||||
// Apply cuffs.
|
||||
var/obj/item/weapon/handcuffs/legcuffs/lcuffs = src
|
||||
lcuffs.loc = target
|
||||
target.legcuffed = lcuffs
|
||||
target.update_inv_legcuffed()
|
||||
if(target.m_intent != "walk")
|
||||
target.m_intent = "walk"
|
||||
if(target.hud_used && user.hud_used.move_intent)
|
||||
target.hud_used.move_intent.icon_state = "walking"
|
||||
return 1
|
||||
@@ -1,7 +1,7 @@
|
||||
/obj/item/weapon/implant/integrated_circuit
|
||||
name = "electronic implant"
|
||||
desc = "It's a case, for building very tiny electronics with."
|
||||
icon = 'icons/obj/electronic_assemblies.dmi'
|
||||
icon = 'icons/obj/integrated_electronics/electronic_setups.dmi'
|
||||
icon_state = "setup_implant"
|
||||
var/obj/item/device/electronic_assembly/implant/IC = null
|
||||
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/obj/item/weapon/implant/neural
|
||||
name = "neural framework implant"
|
||||
desc = "A small metal casing with numerous wires stemming off of it."
|
||||
var/obj/item/organ/internal/brain/my_brain = null
|
||||
var/target_state = null
|
||||
var/robotic_brain = FALSE
|
||||
|
||||
/obj/item/weapon/implant/neural/post_implant(var/mob/source)
|
||||
if(ishuman(source))
|
||||
var/mob/living/carbon/human/H = source
|
||||
if(H.species.has_organ[O_BRAIN])
|
||||
var/obj/item/organ/internal/brain/possible_brain = H.internal_organs_by_name[O_BRAIN]
|
||||
my_brain = possible_brain //Organs will take damage all the same.
|
||||
if(istype(possible_brain) && my_brain.can_assist()) //If the brain is infact a brain, and not something special like an MMI.
|
||||
my_brain.implant_assist(target_state)
|
||||
if(H.isSynthetic() && H.get_FBP_type() != FBP_CYBORG) //If this on an FBP, it's just an extra inefficient attachment to whatever their brain is.
|
||||
robotic_brain = TRUE
|
||||
if(my_brain && my_brain.can_assist())
|
||||
processing_objects.Add(src)
|
||||
|
||||
/obj/item/weapon/implant/neural/Destroy()
|
||||
if(my_brain)
|
||||
if(my_brain.owner)
|
||||
to_chat(my_brain.owner, "<span class='critical'>You feel a pressure in your mind as something is ripped away.</span>")
|
||||
processing_objects.Remove(src)
|
||||
my_brain = null
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/implant/neural/process()
|
||||
if(my_brain && part)
|
||||
if(my_brain.loc != part.loc)
|
||||
to_chat(my_brain.owner, "<span class='critical'>You feel a pressure in your mind as something is ripped away.</span>")
|
||||
meltdown()
|
||||
return 1
|
||||
|
||||
/obj/item/weapon/implant/neural/get_data()
|
||||
var/dat = {"<b>Implant Specifications:</b><BR>
|
||||
<b>Name:</b> Neural Framework Implant<BR>
|
||||
<b>Life:</b> Duration of Brain Function<BR>
|
||||
<b>Important Notes:</b> None<BR>
|
||||
<HR>
|
||||
<b>Implant Details:</b> <BR>
|
||||
<b>Function:</b> Maintains some function or structure of the target's brain.<BR>
|
||||
<b>Special Features:</b><BR>
|
||||
<i>Neuro-Safe</i>- Specialized shell absorbs excess voltages self-destructing the chip if
|
||||
a malfunction occurs thereby attempting to secure the safety of subject.<BR>
|
||||
<b>Integrity:</b> Gradient creates slight risk of being overcharged and frying the
|
||||
circuitry. Resulting faults can cause damage to the host's brain.<HR>
|
||||
Implant Specifics:<BR>"}
|
||||
return dat
|
||||
|
||||
/obj/item/weapon/implant/neural/emp_act(severity)
|
||||
if(!my_brain)
|
||||
return
|
||||
if(malfunction) //Don't malfunction while malfunctioning.
|
||||
return
|
||||
malfunction = MALFUNCTION_TEMPORARY
|
||||
|
||||
var/delay = 10 //Don't let it just get emped twice in a second to kill someone.
|
||||
var/brain_location = my_brain.owner.organs_by_name[my_brain.parent_organ]
|
||||
var/mob/living/L = my_brain.owner
|
||||
switch(severity)
|
||||
if(1)
|
||||
if(prob(10))
|
||||
meltdown()
|
||||
else if(prob(80))
|
||||
my_brain.take_damage(5)
|
||||
if(!robotic_brain)
|
||||
to_chat(L, "<span class='critical'>Something in your [brain_location] burns!</span>")
|
||||
else
|
||||
to_chat(L, "<span class='warning'>Severe fault detected in [brain_location].</span>")
|
||||
if(2)
|
||||
if(prob(80))
|
||||
my_brain.take_damage(3)
|
||||
if(!robotic_brain)
|
||||
to_chat(L, "<span class='danger'>It feels like something is digging into your [brain_location]!</span>")
|
||||
else
|
||||
to_chat(L, "<span class='warning'>Fault detected in [brain_location].</span>")
|
||||
if(3)
|
||||
if(prob(60))
|
||||
my_brain.take_damage(2)
|
||||
if(!robotic_brain)
|
||||
to_chat(L, "<span class='warning'>There is a stabbing pain in your [brain_location]!</span>")
|
||||
if(4)
|
||||
if(prob(40))
|
||||
my_brain.take_damage(1)
|
||||
if(!robotic_brain)
|
||||
to_chat(L, "<span class='warning'>Your [brain_location] aches.</span>")
|
||||
|
||||
spawn(delay)
|
||||
malfunction--
|
||||
|
||||
/obj/item/weapon/implant/neural/meltdown()
|
||||
..()
|
||||
processing_objects.Remove(src)
|
||||
var/mob/living/carbon/human/H = null
|
||||
if(my_brain && my_brain.owner)
|
||||
if(ishuman(my_brain.owner))
|
||||
H = my_brain.owner
|
||||
if(robotic_brain)
|
||||
to_chat(H, "<span class='critical'>WARNING. Fault dete-ct-- in the \the [src].</span>")
|
||||
H.Confuse(30)
|
||||
H.AdjustBlinded(5)
|
||||
my_brain.take_damage(15)
|
||||
my_brain = null
|
||||
return
|
||||
@@ -79,16 +79,6 @@
|
||||
* Knives
|
||||
*/
|
||||
|
||||
// Identical to the tactical knife but nowhere near as stabby.
|
||||
// Kind of like the toy esword compared to the real thing.
|
||||
/obj/item/weapon/material/knife/boot
|
||||
name = "boot knife"
|
||||
desc = "A small fixed-blade knife for putting inside a boot."
|
||||
icon = 'icons/obj/weapons.dmi'
|
||||
icon_state = "tacknife"
|
||||
item_state = "knife"
|
||||
applies_material_colour = 0
|
||||
|
||||
/* From the time of Clowns. Commented out for posterity, and sanity.
|
||||
/obj/item/weapon/material/knife/attack(target as mob, mob/living/user as mob)
|
||||
if ((CLUMSY in user.mutations) && prob(50))
|
||||
|
||||
@@ -74,6 +74,39 @@
|
||||
"<span class='danger'>\The [user] is slitting [TU.his] stomach open with \the [src]! It looks like [TU.hes] trying to commit seppuku.</span>")
|
||||
return (BRUTELOSS)
|
||||
|
||||
// These no longer inherit from hatchets.
|
||||
/obj/item/weapon/material/knife/tacknife
|
||||
name = "tactical knife"
|
||||
desc = "You'd be killing loads of people if this was Medal of Valor: Heroes of Space."
|
||||
icon = 'icons/obj/weapons.dmi'
|
||||
icon_state = "tacknife"
|
||||
item_state = "knife"
|
||||
force_divisor = 0.25 //15 when hardness 60 (steel)
|
||||
attack_verb = list("stabbed", "chopped", "cut")
|
||||
applies_material_colour = 1
|
||||
|
||||
/obj/item/weapon/material/knife/tacknife/combatknife
|
||||
name = "combat knife"
|
||||
desc = "If only you had a boot to put it in."
|
||||
icon = 'icons/obj/weapons.dmi'
|
||||
icon_state = "tacknife"
|
||||
item_state = "knife"
|
||||
force_divisor = 0.34 // 20 with hardness 60 (steel)
|
||||
thrown_force_divisor = 1.75 // 20 with weight 20 (steel)
|
||||
attack_verb = list("sliced", "stabbed", "chopped", "cut")
|
||||
applies_material_colour = 1
|
||||
|
||||
// Identical to the tactical knife but nowhere near as stabby.
|
||||
// Kind of like the toy esword compared to the real thing.
|
||||
/obj/item/weapon/material/knife/tacknife/boot
|
||||
name = "boot knife"
|
||||
desc = "A small fixed-blade knife for putting inside a boot."
|
||||
icon = 'icons/obj/weapons.dmi'
|
||||
icon_state = "tacknife"
|
||||
item_state = "knife"
|
||||
force_divisor = 0.15
|
||||
applies_material_colour = 0
|
||||
|
||||
/obj/item/weapon/material/knife/hook
|
||||
name = "meat hook"
|
||||
desc = "A sharp, metal hook what sticks into things."
|
||||
|
||||
@@ -46,28 +46,6 @@
|
||||
hits = initial(hits)
|
||||
..()
|
||||
|
||||
// These no longer inherit from hatchets.
|
||||
/obj/item/weapon/material/knife/tacknife
|
||||
name = "tactical knife"
|
||||
desc = "You'd be killing loads of people if this was Medal of Valor: Heroes of Space."
|
||||
icon = 'icons/obj/weapons.dmi'
|
||||
icon_state = "tacknife"
|
||||
item_state = "knife"
|
||||
force_divisor = 0.25 //15 when hardness 60 (steel)
|
||||
attack_verb = list("stabbed", "chopped", "cut")
|
||||
applies_material_colour = 1
|
||||
|
||||
/obj/item/weapon/material/knife/tacknife/combatknife
|
||||
name = "combat knife"
|
||||
desc = "If only you had a boot to put it in."
|
||||
icon = 'icons/obj/weapons.dmi'
|
||||
icon_state = "tacknife"
|
||||
item_state = "knife"
|
||||
force_divisor = 0.34 // 20 with hardness 60 (steel)
|
||||
thrown_force_divisor = 1.75 // 20 with weight 20 (steel)
|
||||
attack_verb = list("sliced", "stabbed", "chopped", "cut")
|
||||
applies_material_colour = 1
|
||||
|
||||
/obj/item/weapon/material/minihoe // -- Numbers
|
||||
name = "mini hoe"
|
||||
desc = "It's used for removing weeds or scratching your back."
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/*
|
||||
* Screwdriver
|
||||
*/
|
||||
@@ -123,4 +122,4 @@
|
||||
counterpart.forceMove(get_turf(src))
|
||||
src.forceMove(counterpart)
|
||||
user.put_in_active_hand(counterpart)
|
||||
to_chat(user, "<span class='notice'>You attach the bolt driver bit to [src].</span>")
|
||||
to_chat(user, "<span class='notice'>You attach the bolt driver bit to [src].</span>")
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/*
|
||||
* Wrench
|
||||
*/
|
||||
@@ -69,4 +68,4 @@
|
||||
counterpart.forceMove(get_turf(src))
|
||||
src.forceMove(counterpart)
|
||||
user.put_in_active_hand(counterpart)
|
||||
to_chat(user, "<span class='notice'>You attach the screw driver bit to [src].</span>")
|
||||
to_chat(user, "<span class='notice'>You attach the screw driver bit to [src].</span>")
|
||||
|
||||
@@ -487,4 +487,19 @@
|
||||
/obj/item/toy/prize/seraph,
|
||||
/obj/item/toy/prize/mauler,
|
||||
/obj/item/toy/prize/odysseus,
|
||||
/obj/item/toy/prize/phazon)
|
||||
/obj/item/toy/prize/phazon)
|
||||
|
||||
/obj/random/mouseremains
|
||||
name = "random mouseremains"
|
||||
desc = "For use with mouse spawners."
|
||||
icon = 'icons/obj/assemblies/new_assemblies.dmi'
|
||||
icon_state = "mousetrap"
|
||||
|
||||
/obj/random/mouseremains/item_to_spawn()
|
||||
return pick(/obj/item/device/assembly/mousetrap,
|
||||
/obj/item/device/assembly/mousetrap/armed,
|
||||
/obj/effect/decal/cleanable/spiderling_remains,
|
||||
/obj/effect/decal/cleanable/ash,
|
||||
/obj/item/weapon/cigbutt,
|
||||
/obj/item/weapon/cigbutt/cigarbutt,
|
||||
/obj/effect/decal/remains/mouse)
|
||||
@@ -40,22 +40,25 @@
|
||||
/obj/random/mob/spawn_item() //These should only ever have simple mobs.
|
||||
var/build_path = item_to_spawn()
|
||||
|
||||
var/mob/living/simple_animal/M = new build_path(src.loc)
|
||||
M.ai_inactive = 1 //Don't fight eachother while we're still setting up!
|
||||
if(mob_faction)
|
||||
M.faction = mob_faction
|
||||
M.returns_home = mob_returns_home
|
||||
M.wander = mob_wander
|
||||
M.wander_distance = mob_wander_distance
|
||||
if(overwrite_hostility)
|
||||
M.hostile = mob_hostile
|
||||
M.retaliate = mob_retaliate
|
||||
M.ai_inactive = 0 //Now you can kill eachother if your faction didn't override.
|
||||
var/mob/living/simple_mob/M = new build_path(src.loc)
|
||||
if(!istype(M))
|
||||
return
|
||||
if(M.has_AI())
|
||||
var/datum/ai_holder/AI = M.ai_holder
|
||||
AI.go_sleep() //Don't fight eachother while we're still setting up!
|
||||
AI.returns_home = mob_returns_home
|
||||
AI.wander = mob_wander
|
||||
AI.max_home_distance = mob_wander_distance
|
||||
if(overwrite_hostility)
|
||||
AI.hostile = mob_hostile
|
||||
AI.retaliate = mob_retaliate
|
||||
AI.go_wake() //Now you can kill eachother if your faction didn't override.
|
||||
|
||||
if(pixel_x || pixel_y)
|
||||
M.pixel_x = pixel_x
|
||||
M.pixel_y = pixel_y
|
||||
|
||||
|
||||
/obj/random/mob/sif
|
||||
name = "Random Sif Animal"
|
||||
desc = "This is a random cold weather animal."
|
||||
@@ -186,3 +189,16 @@
|
||||
prob(5);/mob/living/simple_mob/mechanical/hivebot/ranged_damage/laser,
|
||||
prob(5);/mob/living/simple_mob/mechanical/hivebot/ranged_damage/strong,
|
||||
prob(5);/mob/living/simple_mob/mechanical/hivebot/ranged_damage/strong/guard)
|
||||
|
||||
//Mice
|
||||
|
||||
/obj/random/mob/mouse
|
||||
name = "Random Mouse"
|
||||
desc = "This is a random boring maus."
|
||||
icon_state = "mouse_gray"
|
||||
|
||||
/obj/random/mob/mouse/item_to_spawn()
|
||||
return pick(prob(15);/mob/living/simple_mob/animal/passive/mouse/white,
|
||||
prob(30);/mob/living/simple_mob/animal/passive/mouse/brown,
|
||||
prob(30);/mob/living/simple_mob/animal/passive/mouse/gray,
|
||||
prob(25);/obj/random/mouseremains) //because figuring out how to come up with it picking nothing is beyond my coding ability.
|
||||
@@ -15,6 +15,7 @@
|
||||
if(I.density || I.anchored || I == src || !I.simulated)
|
||||
continue
|
||||
I.forceMove(src)
|
||||
update_icon()
|
||||
|
||||
/obj/structure/largecrate/attack_hand(mob/user as mob)
|
||||
to_chat(user, "<span class='notice'>You need a crowbar to pry this open!</span>")
|
||||
@@ -57,6 +58,29 @@
|
||||
ME.attach(H)
|
||||
..()
|
||||
|
||||
/obj/structure/largecrate/vehicle
|
||||
name = "vehicle crate"
|
||||
desc = "It comes in a box for the consumer's sake. ..How is this lighter?"
|
||||
icon_state = "vehiclecrate"
|
||||
|
||||
/obj/structure/largecrate/vehicle/initialize()
|
||||
..()
|
||||
spawn(1)
|
||||
for(var/obj/O in contents)
|
||||
O.update_icon()
|
||||
|
||||
/obj/structure/largecrate/vehicle/bike
|
||||
name = "spacebike crate"
|
||||
starts_with = list(/obj/structure/vehiclecage/spacebike)
|
||||
|
||||
/obj/structure/largecrate/vehicle/quadbike
|
||||
name = "\improper ATV crate"
|
||||
starts_with = list(/obj/structure/vehiclecage/quadbike)
|
||||
|
||||
/obj/structure/largecrate/vehicle/quadtrailer
|
||||
name = "\improper ATV trailer crate"
|
||||
starts_with = list(/obj/structure/vehiclecage/quadtrailer)
|
||||
|
||||
/obj/structure/largecrate/animal
|
||||
icon_state = "mulecrate"
|
||||
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/obj/structure/vehiclecage
|
||||
name = "vehicle cage"
|
||||
desc = "A large metal lattice that seems to exist solely to annoy consumers."
|
||||
icon = 'icons/obj/storage.dmi'
|
||||
icon_state = "vehicle_cage"
|
||||
density = 1
|
||||
var/obj/vehicle/my_vehicle
|
||||
var/my_vehicle_type
|
||||
var/paint_color = "#666666"
|
||||
|
||||
/obj/structure/vehiclecage/examine(mob/user)
|
||||
..()
|
||||
if(my_vehicle)
|
||||
to_chat(user, "<span class='notice'>It seems to contain \the [my_vehicle].</span>")
|
||||
|
||||
/obj/structure/vehiclecage/initialize()
|
||||
. = ..()
|
||||
if(my_vehicle_type)
|
||||
my_vehicle = new my_vehicle_type(src)
|
||||
for(var/obj/I in get_turf(src))
|
||||
if(I.density || I.anchored || I == src || !I.simulated || !istype(I, my_vehicle_type))
|
||||
continue
|
||||
load_vehicle(I)
|
||||
update_icon()
|
||||
|
||||
/obj/structure/vehiclecage/attack_hand(mob/user as mob)
|
||||
to_chat(user, "<span class='notice'>You need a wrench to take this apart!</span>")
|
||||
return
|
||||
|
||||
/obj/structure/vehiclecage/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
var/turf/T = get_turf(src)
|
||||
if(!T)
|
||||
to_chat(user, "<span class='notice'>You can't open this here!</span>")
|
||||
if(W.is_wrench() && do_after(user, 60 * W.toolspeed, src))
|
||||
playsound(loc, W.usesound, 50, 1)
|
||||
disassemble(W, user)
|
||||
user.visible_message("<span class='notice'>[user] begins loosening \the [src]'s bolts.</span>")
|
||||
if(W.is_wirecutter() && do_after(user, 70 * W.toolspeed, src))
|
||||
playsound(loc, W.usesound, 50, 1)
|
||||
disassemble(W, user)
|
||||
user.visible_message("<span class='notice'>[user] begins cutting \the [src]'s bolts.</span>")
|
||||
else
|
||||
return attack_hand(user)
|
||||
|
||||
/obj/structure/vehiclecage/update_icon()
|
||||
..()
|
||||
overlays.Cut()
|
||||
underlays.Cut()
|
||||
|
||||
var/image/framepaint = new(icon = 'icons/obj/storage.dmi', icon_state = "[initial(icon_state)]_a", layer = MOB_LAYER + 1.1)
|
||||
framepaint.plane = MOB_PLANE
|
||||
framepaint.color = paint_color
|
||||
overlays += framepaint
|
||||
|
||||
for(var/obj/vehicle/V in src.contents)
|
||||
var/image/showcase = new(V)
|
||||
showcase.layer = src.layer - 0.1
|
||||
underlays += showcase
|
||||
|
||||
/obj/structure/vehiclecage/MouseDrop_T(var/atom/movable/C, mob/user as mob)
|
||||
if(user && (user.buckled || user.stat || user.restrained() || !Adjacent(user) || !user.Adjacent(C)))
|
||||
return
|
||||
|
||||
var/obj/vehicle/V
|
||||
if(istype(C, /obj/vehicle))
|
||||
V = C
|
||||
if(!V)
|
||||
return
|
||||
|
||||
if(!my_vehicle)
|
||||
load_vehicle(V, user)
|
||||
|
||||
/obj/structure/vehiclecage/proc/load_vehicle(var/obj/vehicle/V, mob/user as mob)
|
||||
if(user)
|
||||
user.visible_message("<span class='notice'>[user] loads \the [V] into \the [src].</span>", \
|
||||
"<span class='notice'>You load \the [V] into \the [src].</span>", \
|
||||
"<span class='notice'>You hear creaking metal.</span>")
|
||||
|
||||
V.forceMove(src)
|
||||
|
||||
paint_color = V.paint_color
|
||||
|
||||
update_icon()
|
||||
|
||||
/obj/structure/vehiclecage/proc/disassemble(obj/item/weapon/W as obj, mob/user as mob)
|
||||
var/turf/T = get_turf(src)
|
||||
new /obj/item/stack/material/steel(src.loc, 5)
|
||||
|
||||
for(var/atom/movable/AM in contents)
|
||||
if(AM.simulated)
|
||||
AM.forceMove(T)
|
||||
|
||||
my_vehicle = null
|
||||
user.visible_message("<span class='notice'>[user] release \the [src].</span>", \
|
||||
"<span class='notice'>You finally release \the [src].</span>", \
|
||||
"<span class='notice'>You hear creaking metal.</span>")
|
||||
qdel(src)
|
||||
|
||||
/obj/structure/vehiclecage/spacebike
|
||||
my_vehicle_type = /obj/vehicle/bike/random
|
||||
|
||||
/obj/structure/vehiclecage/quadbike
|
||||
my_vehicle_type = /obj/vehicle/train/engine/quadbike/random
|
||||
|
||||
/obj/structure/vehiclecage/quadtrailer
|
||||
my_vehicle_type = /obj/vehicle/train/trolley/trailer/random
|
||||
@@ -47,4 +47,4 @@
|
||||
R.ghost_inhabit(M)
|
||||
visible_message("<span class='warning'>The blade shines brightly for a brief moment as [usr] pulls it out of the stone!</span>")
|
||||
log_and_message_admins("successfully acquired a cursed sword.")
|
||||
..()
|
||||
..()
|
||||
|
||||
@@ -317,13 +317,20 @@
|
||||
return
|
||||
|
||||
/obj/structure/girder/cult
|
||||
name = "column"
|
||||
icon= 'icons/obj/cult.dmi'
|
||||
icon_state= "cultgirder"
|
||||
health = 250
|
||||
cover = 70
|
||||
girder_material = DEFAULT_WALL_MATERIAL
|
||||
girder_material = "cult"
|
||||
applies_material_colour = 0
|
||||
|
||||
/obj/structure/girder/cult/update_icon()
|
||||
if(anchored)
|
||||
icon_state = "cultgirder"
|
||||
else
|
||||
icon_state = "displaced"
|
||||
|
||||
/obj/structure/girder/cult/dismantle()
|
||||
new /obj/effect/decal/remains/human(get_turf(src))
|
||||
qdel(src)
|
||||
|
||||
@@ -93,7 +93,9 @@
|
||||
src.health -= damage*0.2
|
||||
spawn(0) healthcheck() //spawn to make sure we return properly if the grille is deleted
|
||||
|
||||
/obj/structure/grille/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
/obj/structure/grille/attackby(obj/item/W as obj, mob/user as mob)
|
||||
if(!istype(W))
|
||||
return
|
||||
if(W.is_wirecutter())
|
||||
if(!shock(user, 100))
|
||||
playsound(src, W.usesound, 100, 1)
|
||||
@@ -107,7 +109,7 @@
|
||||
"<span class='notice'>You have [anchored ? "fastened the grille to" : "unfastened the grille from"] the floor.</span>")
|
||||
return
|
||||
|
||||
//window placing begin //TODO CONVERT PROPERLY TO MATERIAL DATUM
|
||||
//window placing begin //TODO CONVERT PROPERLY TO MATERIAL DATUM
|
||||
else if(istype(W,/obj/item/stack/material))
|
||||
var/obj/item/stack/material/ST = W
|
||||
if(!ST.material.created_window)
|
||||
|
||||
@@ -1,248 +1,107 @@
|
||||
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32
|
||||
|
||||
#define MUSICIAN_HEARCHECK_MINDELAY 4
|
||||
#define INSTRUMENT_MAX_LINE_LENGTH 300
|
||||
#define INSTRUMENT_MAX_LINE_NUMBER 50
|
||||
|
||||
/datum/song
|
||||
var/name = "Untitled"
|
||||
var/list/lines = new()
|
||||
var/tempo = 5
|
||||
var/tempo = 5 // delay between notes
|
||||
|
||||
/obj/structure/device/piano
|
||||
name = "space minimoog"
|
||||
icon = 'icons/obj/musician.dmi'
|
||||
icon_state = "minimoog"
|
||||
anchored = 1
|
||||
density = 1
|
||||
var/datum/song/song
|
||||
var/playing = 0
|
||||
var/help = 0
|
||||
var/edit = 1
|
||||
var/repeat = 0
|
||||
var/playing = 0 // if we're playing
|
||||
var/help = 0 // if help is open
|
||||
var/edit = 1 // if we're in editing mode
|
||||
var/repeat = 0 // number of times remaining to repeat
|
||||
var/max_repeats = 10 // maximum times we can repeat
|
||||
|
||||
/obj/structure/device/piano/New()
|
||||
if(prob(50))
|
||||
name = "space minimoog"
|
||||
desc = "This is a minimoog, like a space piano, but more spacey!"
|
||||
icon_state = "minimoog"
|
||||
var/instrumentDir = "piano" // the folder with the sounds
|
||||
var/instrumentExt = "ogg" // the file extension
|
||||
var/obj/instrumentObj = null // the associated obj playing the sound
|
||||
var/last_hearcheck = 0
|
||||
var/list/hearing_mobs
|
||||
|
||||
/datum/song/New(dir, obj, ext = "ogg")
|
||||
instrumentDir = dir
|
||||
instrumentObj = obj
|
||||
instrumentExt = ext
|
||||
|
||||
/datum/song/Destroy()
|
||||
instrumentObj = null
|
||||
return ..()
|
||||
|
||||
|
||||
// note is a number from 1-7 for A-G
|
||||
// acc is either "b", "n", or "#"
|
||||
// oct is 1-8 (or 9 for C)
|
||||
/datum/song/proc/playnote(note, acc as text, oct)
|
||||
// handle accidental -> B<>C of E<>F
|
||||
if(acc == "b" && (note == 3 || note == 6)) // C or F
|
||||
if(note == 3)
|
||||
oct--
|
||||
note--
|
||||
acc = "n"
|
||||
else if(acc == "#" && (note == 2 || note == 5)) // B or E
|
||||
if(note == 2)
|
||||
oct++
|
||||
note++
|
||||
acc = "n"
|
||||
else if(acc == "#" && (note == 7)) //G#
|
||||
note = 1
|
||||
acc = "b"
|
||||
else if(acc == "#") // mass convert all sharps to flats, octave jump already handled
|
||||
acc = "b"
|
||||
note++
|
||||
|
||||
// check octave, C is allowed to go to 9
|
||||
if(oct < 1 || (note == 3 ? oct > 9 : oct > 8))
|
||||
return
|
||||
|
||||
// now generate name
|
||||
var/soundfile = "sound/instruments/[instrumentDir]/[ascii2text(note+64)][acc][oct].[instrumentExt]"
|
||||
soundfile = file(soundfile)
|
||||
// make sure the note exists
|
||||
if(!fexists(soundfile))
|
||||
return
|
||||
// and play
|
||||
var/turf/source = get_turf(instrumentObj)
|
||||
if((world.time - MUSICIAN_HEARCHECK_MINDELAY) > last_hearcheck)
|
||||
LAZYCLEARLIST(hearing_mobs)
|
||||
for(var/mob/M in hearers(15, source))
|
||||
if(!M.client || !(M.is_preference_enabled(/datum/client_preference/instrument_toggle)))
|
||||
continue
|
||||
LAZYSET(hearing_mobs, M, TRUE)
|
||||
last_hearcheck = world.time
|
||||
var/sound/music_played = sound(soundfile)
|
||||
for(var/i in hearing_mobs)
|
||||
var/mob/M = i
|
||||
M.playsound_local(source, null, 100, falloff = 5, S = music_played)
|
||||
|
||||
/datum/song/proc/updateDialog(mob/user)
|
||||
instrumentObj.updateDialog() // assumes it's an object in world, override if otherwise
|
||||
|
||||
/datum/song/proc/shouldStopPlaying(mob/user)
|
||||
if(instrumentObj)
|
||||
if(!instrumentObj.Adjacent(user) || user.stat)
|
||||
return 1
|
||||
return !instrumentObj.anchored // add special cases to stop in subclasses
|
||||
else
|
||||
name = "space piano"
|
||||
desc = "This is a space piano, like a regular piano, but always in tune! Even if the musician isn't."
|
||||
icon_state = "piano"
|
||||
return 1
|
||||
|
||||
/obj/structure/device/piano/verb/rotate()
|
||||
set name = "Rotate Piano"
|
||||
set category = "Object"
|
||||
set src in oview(1)
|
||||
|
||||
if(ismouse(usr))
|
||||
return
|
||||
else if(!usr || !isturf(usr.loc))
|
||||
return
|
||||
else if(usr.stat || usr.restrained())
|
||||
return
|
||||
else if (istype(usr,/mob/observer/ghost) && !config.ghost_interaction)
|
||||
return
|
||||
else
|
||||
src.set_dir(turn(src.dir, 90))
|
||||
return
|
||||
|
||||
/obj/structure/device/piano/proc/playnote(var/note as text)
|
||||
//world << "Note: [note]"
|
||||
var/soundfile
|
||||
/*BYOND loads resource files at compile time if they are ''. This means you can't really manipulate them dynamically.
|
||||
Tried doing it dynamically at first but its more trouble than its worth. Would have saved many lines tho.*/
|
||||
switch(note)
|
||||
if("Cn1") soundfile = 'sound/piano/Cn1.ogg'
|
||||
if("C#1") soundfile = 'sound/piano/C#1.ogg'
|
||||
if("Db1") soundfile = 'sound/piano/Db1.ogg'
|
||||
if("Dn1") soundfile = 'sound/piano/Dn1.ogg'
|
||||
if("D#1") soundfile = 'sound/piano/D#1.ogg'
|
||||
if("Eb1") soundfile = 'sound/piano/Eb1.ogg'
|
||||
if("En1") soundfile = 'sound/piano/En1.ogg'
|
||||
if("E#1") soundfile = 'sound/piano/E#1.ogg'
|
||||
if("Fb1") soundfile = 'sound/piano/Fb1.ogg'
|
||||
if("Fn1") soundfile = 'sound/piano/Fn1.ogg'
|
||||
if("F#1") soundfile = 'sound/piano/F#1.ogg'
|
||||
if("Gb1") soundfile = 'sound/piano/Gb1.ogg'
|
||||
if("Gn1") soundfile = 'sound/piano/Gn1.ogg'
|
||||
if("G#1") soundfile = 'sound/piano/G#1.ogg'
|
||||
if("Ab1") soundfile = 'sound/piano/Ab1.ogg'
|
||||
if("An1") soundfile = 'sound/piano/An1.ogg'
|
||||
if("A#1") soundfile = 'sound/piano/A#1.ogg'
|
||||
if("Bb1") soundfile = 'sound/piano/Bb1.ogg'
|
||||
if("Bn1") soundfile = 'sound/piano/Bn1.ogg'
|
||||
if("B#1") soundfile = 'sound/piano/B#1.ogg'
|
||||
if("Cb2") soundfile = 'sound/piano/Cb2.ogg'
|
||||
if("Cn2") soundfile = 'sound/piano/Cn2.ogg'
|
||||
if("C#2") soundfile = 'sound/piano/C#2.ogg'
|
||||
if("Db2") soundfile = 'sound/piano/Db2.ogg'
|
||||
if("Dn2") soundfile = 'sound/piano/Dn2.ogg'
|
||||
if("D#2") soundfile = 'sound/piano/D#2.ogg'
|
||||
if("Eb2") soundfile = 'sound/piano/Eb2.ogg'
|
||||
if("En2") soundfile = 'sound/piano/En2.ogg'
|
||||
if("E#2") soundfile = 'sound/piano/E#2.ogg'
|
||||
if("Fb2") soundfile = 'sound/piano/Fb2.ogg'
|
||||
if("Fn2") soundfile = 'sound/piano/Fn2.ogg'
|
||||
if("F#2") soundfile = 'sound/piano/F#2.ogg'
|
||||
if("Gb2") soundfile = 'sound/piano/Gb2.ogg'
|
||||
if("Gn2") soundfile = 'sound/piano/Gn2.ogg'
|
||||
if("G#2") soundfile = 'sound/piano/G#2.ogg'
|
||||
if("Ab2") soundfile = 'sound/piano/Ab2.ogg'
|
||||
if("An2") soundfile = 'sound/piano/An2.ogg'
|
||||
if("A#2") soundfile = 'sound/piano/A#2.ogg'
|
||||
if("Bb2") soundfile = 'sound/piano/Bb2.ogg'
|
||||
if("Bn2") soundfile = 'sound/piano/Bn2.ogg'
|
||||
if("B#2") soundfile = 'sound/piano/B#2.ogg'
|
||||
if("Cb3") soundfile = 'sound/piano/Cb3.ogg'
|
||||
if("Cn3") soundfile = 'sound/piano/Cn3.ogg'
|
||||
if("C#3") soundfile = 'sound/piano/C#3.ogg'
|
||||
if("Db3") soundfile = 'sound/piano/Db3.ogg'
|
||||
if("Dn3") soundfile = 'sound/piano/Dn3.ogg'
|
||||
if("D#3") soundfile = 'sound/piano/D#3.ogg'
|
||||
if("Eb3") soundfile = 'sound/piano/Eb3.ogg'
|
||||
if("En3") soundfile = 'sound/piano/En3.ogg'
|
||||
if("E#3") soundfile = 'sound/piano/E#3.ogg'
|
||||
if("Fb3") soundfile = 'sound/piano/Fb3.ogg'
|
||||
if("Fn3") soundfile = 'sound/piano/Fn3.ogg'
|
||||
if("F#3") soundfile = 'sound/piano/F#3.ogg'
|
||||
if("Gb3") soundfile = 'sound/piano/Gb3.ogg'
|
||||
if("Gn3") soundfile = 'sound/piano/Gn3.ogg'
|
||||
if("G#3") soundfile = 'sound/piano/G#3.ogg'
|
||||
if("Ab3") soundfile = 'sound/piano/Ab3.ogg'
|
||||
if("An3") soundfile = 'sound/piano/An3.ogg'
|
||||
if("A#3") soundfile = 'sound/piano/A#3.ogg'
|
||||
if("Bb3") soundfile = 'sound/piano/Bb3.ogg'
|
||||
if("Bn3") soundfile = 'sound/piano/Bn3.ogg'
|
||||
if("B#3") soundfile = 'sound/piano/B#3.ogg'
|
||||
if("Cb4") soundfile = 'sound/piano/Cb4.ogg'
|
||||
if("Cn4") soundfile = 'sound/piano/Cn4.ogg'
|
||||
if("C#4") soundfile = 'sound/piano/C#4.ogg'
|
||||
if("Db4") soundfile = 'sound/piano/Db4.ogg'
|
||||
if("Dn4") soundfile = 'sound/piano/Dn4.ogg'
|
||||
if("D#4") soundfile = 'sound/piano/D#4.ogg'
|
||||
if("Eb4") soundfile = 'sound/piano/Eb4.ogg'
|
||||
if("En4") soundfile = 'sound/piano/En4.ogg'
|
||||
if("E#4") soundfile = 'sound/piano/E#4.ogg'
|
||||
if("Fb4") soundfile = 'sound/piano/Fb4.ogg'
|
||||
if("Fn4") soundfile = 'sound/piano/Fn4.ogg'
|
||||
if("F#4") soundfile = 'sound/piano/F#4.ogg'
|
||||
if("Gb4") soundfile = 'sound/piano/Gb4.ogg'
|
||||
if("Gn4") soundfile = 'sound/piano/Gn4.ogg'
|
||||
if("G#4") soundfile = 'sound/piano/G#4.ogg'
|
||||
if("Ab4") soundfile = 'sound/piano/Ab4.ogg'
|
||||
if("An4") soundfile = 'sound/piano/An4.ogg'
|
||||
if("A#4") soundfile = 'sound/piano/A#4.ogg'
|
||||
if("Bb4") soundfile = 'sound/piano/Bb4.ogg'
|
||||
if("Bn4") soundfile = 'sound/piano/Bn4.ogg'
|
||||
if("B#4") soundfile = 'sound/piano/B#4.ogg'
|
||||
if("Cb5") soundfile = 'sound/piano/Cb5.ogg'
|
||||
if("Cn5") soundfile = 'sound/piano/Cn5.ogg'
|
||||
if("C#5") soundfile = 'sound/piano/C#5.ogg'
|
||||
if("Db5") soundfile = 'sound/piano/Db5.ogg'
|
||||
if("Dn5") soundfile = 'sound/piano/Dn5.ogg'
|
||||
if("D#5") soundfile = 'sound/piano/D#5.ogg'
|
||||
if("Eb5") soundfile = 'sound/piano/Eb5.ogg'
|
||||
if("En5") soundfile = 'sound/piano/En5.ogg'
|
||||
if("E#5") soundfile = 'sound/piano/E#5.ogg'
|
||||
if("Fb5") soundfile = 'sound/piano/Fb5.ogg'
|
||||
if("Fn5") soundfile = 'sound/piano/Fn5.ogg'
|
||||
if("F#5") soundfile = 'sound/piano/F#5.ogg'
|
||||
if("Gb5") soundfile = 'sound/piano/Gb5.ogg'
|
||||
if("Gn5") soundfile = 'sound/piano/Gn5.ogg'
|
||||
if("G#5") soundfile = 'sound/piano/G#5.ogg'
|
||||
if("Ab5") soundfile = 'sound/piano/Ab5.ogg'
|
||||
if("An5") soundfile = 'sound/piano/An5.ogg'
|
||||
if("A#5") soundfile = 'sound/piano/A#5.ogg'
|
||||
if("Bb5") soundfile = 'sound/piano/Bb5.ogg'
|
||||
if("Bn5") soundfile = 'sound/piano/Bn5.ogg'
|
||||
if("B#5") soundfile = 'sound/piano/B#5.ogg'
|
||||
if("Cb6") soundfile = 'sound/piano/Cb6.ogg'
|
||||
if("Cn6") soundfile = 'sound/piano/Cn6.ogg'
|
||||
if("C#6") soundfile = 'sound/piano/C#6.ogg'
|
||||
if("Db6") soundfile = 'sound/piano/Db6.ogg'
|
||||
if("Dn6") soundfile = 'sound/piano/Dn6.ogg'
|
||||
if("D#6") soundfile = 'sound/piano/D#6.ogg'
|
||||
if("Eb6") soundfile = 'sound/piano/Eb6.ogg'
|
||||
if("En6") soundfile = 'sound/piano/En6.ogg'
|
||||
if("E#6") soundfile = 'sound/piano/E#6.ogg'
|
||||
if("Fb6") soundfile = 'sound/piano/Fb6.ogg'
|
||||
if("Fn6") soundfile = 'sound/piano/Fn6.ogg'
|
||||
if("F#6") soundfile = 'sound/piano/F#6.ogg'
|
||||
if("Gb6") soundfile = 'sound/piano/Gb6.ogg'
|
||||
if("Gn6") soundfile = 'sound/piano/Gn6.ogg'
|
||||
if("G#6") soundfile = 'sound/piano/G#6.ogg'
|
||||
if("Ab6") soundfile = 'sound/piano/Ab6.ogg'
|
||||
if("An6") soundfile = 'sound/piano/An6.ogg'
|
||||
if("A#6") soundfile = 'sound/piano/A#6.ogg'
|
||||
if("Bb6") soundfile = 'sound/piano/Bb6.ogg'
|
||||
if("Bn6") soundfile = 'sound/piano/Bn6.ogg'
|
||||
if("B#6") soundfile = 'sound/piano/B#6.ogg'
|
||||
if("Cb7") soundfile = 'sound/piano/Cb7.ogg'
|
||||
if("Cn7") soundfile = 'sound/piano/Cn7.ogg'
|
||||
if("C#7") soundfile = 'sound/piano/C#7.ogg'
|
||||
if("Db7") soundfile = 'sound/piano/Db7.ogg'
|
||||
if("Dn7") soundfile = 'sound/piano/Dn7.ogg'
|
||||
if("D#7") soundfile = 'sound/piano/D#7.ogg'
|
||||
if("Eb7") soundfile = 'sound/piano/Eb7.ogg'
|
||||
if("En7") soundfile = 'sound/piano/En7.ogg'
|
||||
if("E#7") soundfile = 'sound/piano/E#7.ogg'
|
||||
if("Fb7") soundfile = 'sound/piano/Fb7.ogg'
|
||||
if("Fn7") soundfile = 'sound/piano/Fn7.ogg'
|
||||
if("F#7") soundfile = 'sound/piano/F#7.ogg'
|
||||
if("Gb7") soundfile = 'sound/piano/Gb7.ogg'
|
||||
if("Gn7") soundfile = 'sound/piano/Gn7.ogg'
|
||||
if("G#7") soundfile = 'sound/piano/G#7.ogg'
|
||||
if("Ab7") soundfile = 'sound/piano/Ab7.ogg'
|
||||
if("An7") soundfile = 'sound/piano/An7.ogg'
|
||||
if("A#7") soundfile = 'sound/piano/A#7.ogg'
|
||||
if("Bb7") soundfile = 'sound/piano/Bb7.ogg'
|
||||
if("Bn7") soundfile = 'sound/piano/Bn7.ogg'
|
||||
if("B#7") soundfile = 'sound/piano/B#7.ogg'
|
||||
if("Cb8") soundfile = 'sound/piano/Cb8.ogg'
|
||||
if("Cn8") soundfile = 'sound/piano/Cn8.ogg'
|
||||
if("C#8") soundfile = 'sound/piano/C#8.ogg'
|
||||
if("Db8") soundfile = 'sound/piano/Db8.ogg'
|
||||
if("Dn8") soundfile = 'sound/piano/Dn8.ogg'
|
||||
if("D#8") soundfile = 'sound/piano/D#8.ogg'
|
||||
if("Eb8") soundfile = 'sound/piano/Eb8.ogg'
|
||||
if("En8") soundfile = 'sound/piano/En8.ogg'
|
||||
if("E#8") soundfile = 'sound/piano/E#8.ogg'
|
||||
if("Fb8") soundfile = 'sound/piano/Fb8.ogg'
|
||||
if("Fn8") soundfile = 'sound/piano/Fn8.ogg'
|
||||
if("F#8") soundfile = 'sound/piano/F#8.ogg'
|
||||
if("Gb8") soundfile = 'sound/piano/Gb8.ogg'
|
||||
if("Gn8") soundfile = 'sound/piano/Gn8.ogg'
|
||||
if("G#8") soundfile = 'sound/piano/G#8.ogg'
|
||||
if("Ab8") soundfile = 'sound/piano/Ab8.ogg'
|
||||
if("An8") soundfile = 'sound/piano/An8.ogg'
|
||||
if("A#8") soundfile = 'sound/piano/A#8.ogg'
|
||||
if("Bb8") soundfile = 'sound/piano/Bb8.ogg'
|
||||
if("Bn8") soundfile = 'sound/piano/Bn8.ogg'
|
||||
if("B#8") soundfile = 'sound/piano/B#8.ogg'
|
||||
if("Cb9") soundfile = 'sound/piano/Cb9.ogg'
|
||||
if("Cn9") soundfile = 'sound/piano/Cn9.ogg'
|
||||
else return
|
||||
|
||||
//hearers(15, src) << sound(soundfile)
|
||||
var/turf/source = get_turf(src)
|
||||
for(var/mob/M in hearers(15, source))
|
||||
M.playsound_local(source, file(soundfile), 100, falloff = 5)
|
||||
|
||||
|
||||
/obj/structure/device/piano/proc/playsong()
|
||||
do
|
||||
/datum/song/proc/playsong(mob/user)
|
||||
while(repeat >= 0)
|
||||
var/cur_oct[7]
|
||||
var/cur_acc[7]
|
||||
for(var/i = 1 to 7)
|
||||
cur_oct[i] = "3"
|
||||
cur_oct[i] = 3
|
||||
cur_acc[i] = "n"
|
||||
|
||||
for(var/line in song.lines)
|
||||
//world << line
|
||||
for(var/line in lines)
|
||||
for(var/beat in splittext(lowertext(line), ","))
|
||||
//world << "beat: [beat]"
|
||||
var/list/notes = splittext(beat, "/")
|
||||
for(var/note in splittext(notes[1], "-"))
|
||||
//world << "note: [note]"
|
||||
if(!playing || !anchored)//If the piano is playing, or is loose
|
||||
if(!playing || shouldStopPlaying(user))//If the instrument is playing, or special case
|
||||
playing = 0
|
||||
return
|
||||
if(lentext(note) == 0)
|
||||
@@ -259,49 +118,47 @@
|
||||
else if(ni == "s")
|
||||
cur_acc[cur_note] = "#" // so shift is never required
|
||||
else
|
||||
cur_oct[cur_note] = ni
|
||||
playnote(uppertext(copytext(note,1,2)) + cur_acc[cur_note] + cur_oct[cur_note])
|
||||
cur_oct[cur_note] = text2num(ni)
|
||||
playnote(cur_note, cur_acc[cur_note], cur_oct[cur_note])
|
||||
if(notes.len >= 2 && text2num(notes[2]))
|
||||
sleep(song.tempo / text2num(notes[2]))
|
||||
sleep(sanitize_tempo(tempo / text2num(notes[2])))
|
||||
else
|
||||
sleep(song.tempo)
|
||||
if(repeat > 0)
|
||||
repeat-- //Infinite loops are baaaad.
|
||||
while(repeat > 0)
|
||||
sleep(tempo)
|
||||
repeat--
|
||||
playing = 0
|
||||
updateUsrDialog()
|
||||
repeat = 0
|
||||
updateDialog(user)
|
||||
|
||||
/obj/structure/device/piano/attack_hand(var/mob/user as mob)
|
||||
if(!anchored)
|
||||
return
|
||||
|
||||
usr.machine = src
|
||||
var/dat = "<HEAD><TITLE>Piano</TITLE></HEAD><BODY>"
|
||||
|
||||
if(song)
|
||||
if(song.lines.len > 0 && !(playing))
|
||||
dat += "<A href='?src=\ref[src];play=1'>Play Song</A><BR><BR>"
|
||||
dat += "<A href='?src=\ref[src];repeat=1'>Repeat Song: [repeat] times.</A><BR><BR>"
|
||||
if(playing)
|
||||
dat += "<A href='?src=\ref[src];stop=1'>Stop Playing</A><BR>"
|
||||
dat += "Repeats left: [repeat].<BR><BR>"
|
||||
/datum/song/proc/interact(mob/user)
|
||||
var/dat = ""
|
||||
if(lines.len > 0)
|
||||
dat += "<H3>Playback</H3>"
|
||||
if(!playing)
|
||||
dat += {"<A href='?src=\ref[src];play=1'>Play</A> <SPAN CLASS='linkOn'>Stop</SPAN><BR><BR>
|
||||
Repeat Song:
|
||||
[repeat > 0 ? "<A href='?src=\ref[src];repeat=-10'>-</A><A href='?src=\ref[src];repeat=-1'>-</A>" : "<SPAN CLASS='linkOff'>-</SPAN><SPAN CLASS='linkOff'>-</SPAN>"]
|
||||
[repeat] times
|
||||
[repeat < max_repeats ? "<A href='?src=\ref[src];repeat=1'>+</A><A href='?src=\ref[src];repeat=10'>+</A>" : "<SPAN CLASS='linkOff'>+</SPAN><SPAN CLASS='linkOff'>+</SPAN>"]
|
||||
<BR>"}
|
||||
else
|
||||
dat += {"<SPAN CLASS='linkOn'>Play</SPAN> <A href='?src=\ref[src];stop=1'>Stop</A><BR>
|
||||
Repeats left: <B>[repeat]</B><BR>"}
|
||||
if(!edit)
|
||||
dat += "<A href='?src=\ref[src];edit=2'>Show Editor</A><BR><BR>"
|
||||
dat += "<BR><B><A href='?src=\ref[src];edit=2'>Show Editor</A></B><BR>"
|
||||
else
|
||||
dat += "<A href='?src=\ref[src];edit=1'>Hide Editor</A><BR>"
|
||||
dat += "<A href='?src=\ref[src];newsong=1'>Start a New Song</A><BR>"
|
||||
dat += "<A href='?src=\ref[src];import=1'>Import a Song</A><BR><BR>"
|
||||
if(song)
|
||||
var/calctempo = (10/song.tempo)*60
|
||||
dat += "Tempo : <A href='?src=\ref[src];tempo=10'>-</A><A href='?src=\ref[src];tempo=1'>-</A> [calctempo] BPM <A href='?src=\ref[src];tempo=-1'>+</A><A href='?src=\ref[src];tempo=-10'>+</A><BR><BR>"
|
||||
var/linecount = 0
|
||||
for(var/line in song.lines)
|
||||
linecount += 1
|
||||
dat += "Line [linecount]: [line] <A href='?src=\ref[src];deleteline=[linecount]'>Delete Line</A> <A href='?src=\ref[src];modifyline=[linecount]'>Modify Line</A><BR>"
|
||||
dat += "<A href='?src=\ref[src];newline=1'>Add Line</A><BR><BR>"
|
||||
var/bpm = round(600 / tempo)
|
||||
dat += {"<H3>Editing</H3>
|
||||
<B><A href='?src=\ref[src];edit=1'>Hide Editor</A></B>
|
||||
<A href='?src=\ref[src];newsong=1'>Start a New Song</A>
|
||||
<A href='?src=\ref[src];import=1'>Import a Song</A><BR><BR>
|
||||
Tempo: <A href='?src=\ref[src];tempo=[world.tick_lag]'>-</A> [bpm] BPM <A href='?src=\ref[src];tempo=-[world.tick_lag]'>+</A><BR><BR>"}
|
||||
var/linecount = 0
|
||||
for(var/line in lines)
|
||||
linecount += 1
|
||||
dat += "Line [linecount]: <A href='?src=\ref[src];modifyline=[linecount]'>Edit</A> <A href='?src=\ref[src];deleteline=[linecount]'>X</A> [line]<BR>"
|
||||
dat += "<A href='?src=\ref[src];newline=1'>Add Line</A><BR><BR>"
|
||||
if(help)
|
||||
dat += "<A href='?src=\ref[src];help=1'>Hide Help</A><BR>"
|
||||
dat += {"
|
||||
dat += {"<B><A href='?src=\ref[src];help=1'>Hide Help</A></B><BR>
|
||||
Lines are a series of chords, separated by commas (,), each with notes seperated by hyphens (-).<br>
|
||||
Every note in a chord will play together, with chord timed by the tempo.<br>
|
||||
<br>
|
||||
@@ -313,120 +170,183 @@
|
||||
A pause may be denoted by an empty chord: <i>C,E,,C,G</i><br>
|
||||
To make a chord be a different time, end it with /x, where the chord length will be length<br>
|
||||
defined by tempo / x: <i>C,G/2,E/4</i><br>
|
||||
Combined, an example is: <i>E-E4/4,/2,G#/8,B/8,E3-E4/4</i>
|
||||
Combined, an example is: <i>E-E4/4,F#/2,G#/8,B/8,E3-E4/4</i>
|
||||
<br>
|
||||
Lines may be up to 50 characters.<br>
|
||||
A song may only contain up to 50 lines.<br>
|
||||
"}
|
||||
else
|
||||
dat += "<A href='?src=\ref[src];help=2'>Show Help</A><BR>"
|
||||
dat += "</BODY></HTML>"
|
||||
user << browse(dat, "window=piano;size=700x300")
|
||||
onclose(user, "piano")
|
||||
dat += "<B><A href='?src=\ref[src];help=2'>Show Help</A></B><BR>"
|
||||
var/datum/browser/popup = new(user, "instrument", instrumentObj.name, 700, 500)
|
||||
popup.set_content(dat)
|
||||
popup.set_title_image(user.browse_rsc_icon(instrumentObj.icon, instrumentObj.icon_state))
|
||||
popup.open()
|
||||
|
||||
/obj/structure/device/piano/Topic(href, href_list)
|
||||
/datum/song/Topic(href, href_list)
|
||||
if(!instrumentObj.Adjacent(usr) || usr.stat)
|
||||
usr << browse(null, "window=instrument")
|
||||
usr.unset_machine()
|
||||
return
|
||||
instrumentObj.add_fingerprint(usr)
|
||||
if(href_list["newsong"])
|
||||
lines = new()
|
||||
tempo = sanitize_tempo(5) // default 120 BPM
|
||||
name = ""
|
||||
else if(href_list["import"])
|
||||
var/t = ""
|
||||
do
|
||||
t = html_encode(input(usr, "Please paste the entire song, formatted:", text("[]", name), t) as message)
|
||||
if(!in_range(instrumentObj, usr))
|
||||
return
|
||||
if(lentext(t) >= INSTRUMENT_MAX_LINE_LENGTH*INSTRUMENT_MAX_LINE_NUMBER)
|
||||
var/cont = input(usr, "Your message is too long! Would you like to continue editing it?", "", "yes") in list("yes", "no")
|
||||
if(cont == "no")
|
||||
break
|
||||
while(lentext(t) > INSTRUMENT_MAX_LINE_LENGTH*INSTRUMENT_MAX_LINE_NUMBER)
|
||||
//split into lines
|
||||
spawn()
|
||||
lines = splittext(t, "\n")
|
||||
if(copytext(lines[1],1,6) == "BPM: ")
|
||||
tempo = sanitize_tempo(600 / text2num(copytext(lines[1],6)))
|
||||
lines.Cut(1,2)
|
||||
else
|
||||
tempo = sanitize_tempo(5) // default 120 BPM
|
||||
if(lines.len > INSTRUMENT_MAX_LINE_NUMBER)
|
||||
usr << "Too many lines!"
|
||||
lines.Cut(INSTRUMENT_MAX_LINE_NUMBER+1)
|
||||
var/linenum = 1
|
||||
for(var/l in lines)
|
||||
if(lentext(l) > INSTRUMENT_MAX_LINE_LENGTH)
|
||||
usr << "Line [linenum] too long!"
|
||||
lines.Remove(l)
|
||||
else
|
||||
linenum++
|
||||
updateDialog(usr) // make sure updates when complete
|
||||
else if(href_list["help"])
|
||||
help = text2num(href_list["help"]) - 1
|
||||
else if(href_list["edit"])
|
||||
edit = text2num(href_list["edit"]) - 1
|
||||
if(href_list["repeat"]) //Changing this from a toggle to a number of repeats to avoid infinite loops.
|
||||
if(playing)
|
||||
return //So that people cant keep adding to repeat. If the do it intentionally, it could result in the server crashing.
|
||||
repeat += round(text2num(href_list["repeat"]))
|
||||
if(repeat < 0)
|
||||
repeat = 0
|
||||
if(repeat > max_repeats)
|
||||
repeat = max_repeats
|
||||
else if(href_list["tempo"])
|
||||
tempo = sanitize_tempo(tempo + text2num(href_list["tempo"]))
|
||||
else if(href_list["play"])
|
||||
playing = 1
|
||||
spawn()
|
||||
playsong(usr)
|
||||
else if(href_list["newline"])
|
||||
var/newline = html_encode(input("Enter your line: ", instrumentObj.name) as text|null)
|
||||
if(!newline || !in_range(instrumentObj, usr))
|
||||
return
|
||||
if(lines.len > INSTRUMENT_MAX_LINE_NUMBER)
|
||||
return
|
||||
if(lentext(newline) > INSTRUMENT_MAX_LINE_LENGTH)
|
||||
newline = copytext(newline, 1, INSTRUMENT_MAX_LINE_LENGTH)
|
||||
lines.Add(newline)
|
||||
else if(href_list["deleteline"])
|
||||
var/num = round(text2num(href_list["deleteline"]))
|
||||
if(num > lines.len || num < 1)
|
||||
return
|
||||
lines.Cut(num, num+1)
|
||||
else if(href_list["modifyline"])
|
||||
var/num = round(text2num(href_list["modifyline"]),1)
|
||||
var/content = html_encode(input("Enter your line: ", instrumentObj.name, lines[num]) as text|null)
|
||||
if(!content || !in_range(instrumentObj, usr))
|
||||
return
|
||||
if(lentext(content) > INSTRUMENT_MAX_LINE_LENGTH)
|
||||
content = copytext(content, 1, INSTRUMENT_MAX_LINE_LENGTH)
|
||||
if(num > lines.len || num < 1)
|
||||
return
|
||||
lines[num] = content
|
||||
else if(href_list["stop"])
|
||||
playing = 0
|
||||
updateDialog(usr)
|
||||
return
|
||||
|
||||
if(!in_range(src, usr) || issilicon(usr) || !anchored || !usr.canmove || usr.restrained())
|
||||
usr << browse(null, "window=piano;size=700x300")
|
||||
onclose(usr, "piano")
|
||||
/datum/song/proc/sanitize_tempo(new_tempo)
|
||||
new_tempo = abs(new_tempo)
|
||||
return max(round(new_tempo, world.tick_lag), world.tick_lag)
|
||||
|
||||
// subclass for handheld instruments, like violin
|
||||
/datum/song/handheld
|
||||
|
||||
/datum/song/handheld/updateDialog(mob/user)
|
||||
instrumentObj.interact(user)
|
||||
|
||||
/datum/song/handheld/shouldStopPlaying()
|
||||
if(instrumentObj)
|
||||
return !isliving(instrumentObj.loc)
|
||||
else
|
||||
return 1
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
/obj/structure/device/piano
|
||||
name = "space piano"
|
||||
desc = "This is a space piano; just like a regular piano, but always in tune! Even if the musician isn't."
|
||||
icon = 'icons/obj/musician.dmi'
|
||||
icon_state = "piano"
|
||||
anchored = 1
|
||||
density = 1
|
||||
var/datum/song/song
|
||||
|
||||
/obj/structure/device/piano/minimoog
|
||||
name = "space minimoog"
|
||||
icon_state = "minimoog"
|
||||
desc = "This is a minimoog; just like a space piano, but more spacey!"
|
||||
|
||||
/obj/structure/device/piano/New()
|
||||
..()
|
||||
song = new("piano", src)
|
||||
|
||||
if(prob(50))
|
||||
name = "space minimoog"
|
||||
desc = "This is a minimoog, like a space piano, but more spacey!"
|
||||
icon_state = "minimoog"
|
||||
else
|
||||
name = "space piano"
|
||||
desc = "This is a space piano, like a regular piano, but always in tune! Even if the musician isn't."
|
||||
icon_state = "piano"
|
||||
|
||||
/obj/structure/device/piano/Destroy()
|
||||
qdel(song)
|
||||
song = null
|
||||
..()
|
||||
|
||||
/obj/structure/device/piano/verb/rotate()
|
||||
set name = "Rotate Piano"
|
||||
set category = "Object"
|
||||
set src in oview(1)
|
||||
|
||||
if(istype(usr,/mob/living/simple_mob/animal/passive/mouse))
|
||||
return
|
||||
else if(!usr || !isturf(usr.loc))
|
||||
return
|
||||
else if(usr.stat || usr.restrained())
|
||||
return
|
||||
else if (istype(usr,/mob/observer/ghost) && !config.ghost_interaction)
|
||||
return
|
||||
else
|
||||
src.set_dir(turn(src.dir, 90))
|
||||
return
|
||||
|
||||
if(href_list["newsong"])
|
||||
song = new()
|
||||
else if(song)
|
||||
if(href_list["repeat"]) //Changing this from a toggle to a number of repeats to avoid infinite loops.
|
||||
if(playing) return //So that people cant keep adding to repeat. If the do it intentionally, it could result in the server crashing.
|
||||
var/tempnum = input("How many times do you want to repeat this piece? (max:10)") as num|null
|
||||
if(tempnum > 10)
|
||||
tempnum = 10
|
||||
if(tempnum < 0)
|
||||
tempnum = 0
|
||||
repeat = round(tempnum)
|
||||
/obj/structure/device/piano/attack_hand(mob/user)
|
||||
if(!user.IsAdvancedToolUser())
|
||||
to_chat(user, "<span class='warning'>You don't have the dexterity to do this!</span>")
|
||||
return 1
|
||||
interact(user)
|
||||
|
||||
else if(href_list["tempo"])
|
||||
song.tempo += round(text2num(href_list["tempo"]))
|
||||
if(song.tempo < 1)
|
||||
song.tempo = 1
|
||||
/obj/structure/device/piano/interact(mob/user)
|
||||
if(!user || !anchored)
|
||||
return
|
||||
|
||||
else if(href_list["play"])
|
||||
if(song)
|
||||
playing = 1
|
||||
spawn() playsong()
|
||||
|
||||
else if(href_list["newline"])
|
||||
var/newline = html_encode(input("Enter your line: ", "Piano") as text|null)
|
||||
if(!newline)
|
||||
return
|
||||
if(song.lines.len > 50)
|
||||
return
|
||||
if(lentext(newline) > 50)
|
||||
newline = copytext(newline, 1, 50)
|
||||
song.lines.Add(newline)
|
||||
|
||||
else if(href_list["deleteline"])
|
||||
var/num = round(text2num(href_list["deleteline"]))
|
||||
if(num > song.lines.len || num < 1)
|
||||
return
|
||||
song.lines.Cut(num, num+1)
|
||||
|
||||
else if(href_list["modifyline"])
|
||||
var/num = round(text2num(href_list["modifyline"]),1)
|
||||
var/content = html_encode(input("Enter your line: ", "Piano", song.lines[num]) as text|null)
|
||||
if(!content)
|
||||
return
|
||||
if(lentext(content) > 50)
|
||||
content = copytext(content, 1, 50)
|
||||
if(num > song.lines.len || num < 1)
|
||||
return
|
||||
song.lines[num] = content
|
||||
|
||||
else if(href_list["stop"])
|
||||
playing = 0
|
||||
|
||||
else if(href_list["help"])
|
||||
help = text2num(href_list["help"]) - 1
|
||||
|
||||
else if(href_list["edit"])
|
||||
edit = text2num(href_list["edit"]) - 1
|
||||
|
||||
else if(href_list["import"])
|
||||
var/t = ""
|
||||
do
|
||||
t = html_encode(input(usr, "Please paste the entire song, formatted:", text("[]", src.name), t) as message)
|
||||
if (!in_range(src, usr))
|
||||
return
|
||||
|
||||
if(lentext(t) >= 3072)
|
||||
var/cont = input(usr, "Your message is too long! Would you like to continue editing it?", "", "yes") in list("yes", "no")
|
||||
if(cont == "no")
|
||||
break
|
||||
while(lentext(t) > 3072)
|
||||
|
||||
//split into lines
|
||||
spawn()
|
||||
var/list/lines = splittext(t, "\n")
|
||||
var/tempo = 5
|
||||
if(copytext(lines[1],1,6) == "BPM: ")
|
||||
tempo = 600 / text2num(copytext(lines[1],6))
|
||||
lines.Cut(1,2)
|
||||
if(lines.len > 50)
|
||||
usr << "Too many lines!"
|
||||
lines.Cut(51)
|
||||
var/linenum = 1
|
||||
for(var/l in lines)
|
||||
if(lentext(l) > 50)
|
||||
usr << "Line [linenum] too long!"
|
||||
lines.Remove(l)
|
||||
else
|
||||
linenum++
|
||||
song = new()
|
||||
song.lines = lines
|
||||
song.tempo = tempo
|
||||
updateUsrDialog()
|
||||
|
||||
add_fingerprint(usr)
|
||||
updateUsrDialog()
|
||||
return
|
||||
user.set_machine(src)
|
||||
song.interact(user)
|
||||
|
||||
/obj/structure/device/piano/attackby(obj/item/O as obj, mob/user as mob)
|
||||
if(O.is_wrench())
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/obj/structure/prop/nest
|
||||
name = "diyaab den"
|
||||
desc = "A den of some creature."
|
||||
icon = 'icons/obj/structures.dmi'
|
||||
icon_state = "bonfire"
|
||||
density = TRUE
|
||||
anchored = TRUE
|
||||
interaction_message = "<span class='warning'>You feel like you shouldn't be sticking your nose into a wild animal's den.</span>"
|
||||
|
||||
var/disturbance_spawn_chance = 20
|
||||
var/last_spawn
|
||||
var/spawn_delay = 150
|
||||
var/randomize_spawning = FALSE
|
||||
var/creature_types = list(/mob/living/simple_mob/animal/sif/diyaab)
|
||||
var/list/den_mobs
|
||||
var/den_faction //The faction of any spawned creatures.
|
||||
var/max_creatures = 3 //Maximum number of living creatures this nest can have at one time.
|
||||
|
||||
var/tally = 0 //The counter referenced against total_creature_max, or just to see how many mobs it has spawned.
|
||||
var/total_creature_max //If set, it can spawn this many creatures, total, ever.
|
||||
|
||||
/obj/structure/prop/nest/initialize()
|
||||
..()
|
||||
den_mobs = list()
|
||||
processing_objects |= src
|
||||
last_spawn = world.time
|
||||
if(randomize_spawning) //Not the biggest shift in spawntime, but it's here.
|
||||
var/delayshift_clamp = spawn_delay / 10
|
||||
var/delayshift = rand(delayshift_clamp, -1 * delayshift_clamp)
|
||||
spawn_delay += delayshift
|
||||
|
||||
/obj/structure/prop/nest/Destroy()
|
||||
den_mobs = null
|
||||
processing_objects -= src
|
||||
..()
|
||||
|
||||
/obj/structure/prop/nest/attack_hand(mob/living/user) // Used to tell the player that this isn't useful for anything.
|
||||
..()
|
||||
if(user && prob(disturbance_spawn_chance))
|
||||
spawn_creature(get_turf(src))
|
||||
|
||||
/obj/structure/prop/nest/process()
|
||||
update_creatures()
|
||||
if(world.time > last_spawn + spawn_delay)
|
||||
spawn_creature(get_turf(src))
|
||||
|
||||
/obj/structure/prop/nest/proc/spawn_creature(var/turf/spawnpoint)
|
||||
update_creatures() //Paranoia.
|
||||
if(total_creature_max && tally >= total_creature_max)
|
||||
return
|
||||
if(istype(spawnpoint) && den_mobs.len < max_creatures)
|
||||
last_spawn = world.time
|
||||
var/spawn_choice = pick(creature_types)
|
||||
var/mob/living/L = new spawn_choice
|
||||
if(den_faction)
|
||||
L.faction = den_faction
|
||||
visible_message("<span class='warning'>\The [L] crawls out of \the [src].</span>")
|
||||
den_mobs += L
|
||||
tally++
|
||||
|
||||
/obj/structure/prop/nest/proc/remove_creature(var/mob/target)
|
||||
den_mobs -= target
|
||||
|
||||
/obj/structure/prop/nest/proc/update_creatures()
|
||||
for(var/mob/living/L in den_mobs)
|
||||
if(L.stat == 2)
|
||||
remove_creature(L)
|
||||
@@ -34,11 +34,9 @@
|
||||
continue
|
||||
if(SA == target) // We (presumably) already hit the target before cleave() was called. orange() should prevent this but just to be safe...
|
||||
continue
|
||||
if(user.faction == SA.faction) // Avoid friendly fire.
|
||||
continue
|
||||
if(!SA.Adjacent(user) || !SA.Adjacent(target)) // Cleaving only hits mobs near the target mob and user.
|
||||
continue
|
||||
if(resolve_attackby(SA, user)) // Hit them with the weapon. This won't cause recursive cleaving due to the cleaving variable being set to true.
|
||||
if(resolve_attackby(SA, user, attack_modifier = 0.5)) // Hit them with the weapon. This won't cause recursive cleaving due to the cleaving variable being set to true.
|
||||
hit_mobs++
|
||||
|
||||
cleave_visual(user, target)
|
||||
|
||||
Reference in New Issue
Block a user