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:
Neerti
2018-09-22 17:24:00 -05:00
committed by Anewbe
parent b01183ef0c
commit f98e9bf96c
677 changed files with 7904 additions and 3235 deletions
+5
View File
@@ -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
+3
View File
@@ -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
+62 -69
View File
@@ -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."
+1 -1
View File
@@ -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
+30 -381
View File
@@ -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"
+1 -1
View File
@@ -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
+50 -38
View File
@@ -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>")
+16 -1
View File
@@ -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)
+27 -11
View File
@@ -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.")
..()
..()
+8 -1
View File
@@ -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)
+4 -2
View File
@@ -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)
+286 -366
View File
@@ -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)
+1 -3
View File
@@ -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)