diff --git a/code/__DEFINES/jobs.dm b/code/__DEFINES/jobs.dm
index ae58443302..82acf13dcf 100644
--- a/code/__DEFINES/jobs.dm
+++ b/code/__DEFINES/jobs.dm
@@ -1,43 +1,43 @@
-
-#define ENGSEC (1<<0)
-
-#define CAPTAIN (1<<0)
-#define HOS (1<<1)
-#define WARDEN (1<<2)
-#define DETECTIVE (1<<3)
-#define OFFICER (1<<4)
-#define CHIEF (1<<5)
-#define ENGINEER (1<<6)
-#define ATMOSTECH (1<<7)
-#define ROBOTICIST (1<<8)
-#define AI_JF (1<<9)
-#define CYBORG (1<<10)
-
-
-#define MEDSCI (1<<1)
-
-#define RD_JF (1<<0)
-#define SCIENTIST (1<<1)
-#define CHEMIST (1<<2)
-#define CMO_JF (1<<3)
-#define DOCTOR (1<<4)
-#define GENETICIST (1<<5)
-#define VIROLOGIST (1<<6)
-
-
-#define CIVILIAN (1<<2)
-
-#define HOP (1<<0)
-#define BARTENDER (1<<1)
-#define BOTANIST (1<<2)
-#define COOK (1<<3)
-#define JANITOR (1<<4)
-#define CURATOR (1<<5)
-#define QUARTERMASTER (1<<6)
-#define CARGOTECH (1<<7)
-#define MINER (1<<8)
-#define LAWYER (1<<9)
-#define CHAPLAIN (1<<10)
-#define CLOWN (1<<11)
-#define MIME (1<<12)
+
+#define ENGSEC (1<<0)
+
+#define CAPTAIN (1<<0)
+#define HOS (1<<1)
+#define WARDEN (1<<2)
+#define DETECTIVE (1<<3)
+#define OFFICER (1<<4)
+#define CHIEF (1<<5)
+#define ENGINEER (1<<6)
+#define ATMOSTECH (1<<7)
+#define ROBOTICIST (1<<8)
+#define AI_JF (1<<9)
+#define CYBORG (1<<10)
+
+
+#define MEDSCI (1<<1)
+
+#define RD_JF (1<<0)
+#define SCIENTIST (1<<1)
+#define CHEMIST (1<<2)
+#define CMO_JF (1<<3)
+#define DOCTOR (1<<4)
+#define GENETICIST (1<<5)
+#define VIROLOGIST (1<<6)
+
+
+#define CIVILIAN (1<<2)
+
+#define HOP (1<<0)
+#define BARTENDER (1<<1)
+#define BOTANIST (1<<2)
+#define COOK (1<<3)
+#define JANITOR (1<<4)
+#define CURATOR (1<<5)
+#define QUARTERMASTER (1<<6)
+#define CARGOTECH (1<<7)
+#define MINER (1<<8)
+#define LAWYER (1<<9)
+#define CHAPLAIN (1<<10)
+#define CLOWN (1<<11)
+#define MIME (1<<12)
#define ASSISTANT (1<<13)
\ No newline at end of file
diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm
index 83ecedd319..ce7014d765 100644
--- a/code/_onclick/hud/_defines.dm
+++ b/code/_onclick/hud/_defines.dm
@@ -1,162 +1,162 @@
-/*
- These defines specificy screen locations. For more information, see the byond documentation on the screen_loc var.
-
- The short version:
-
- Everything is encoded as strings because apparently that's how Byond rolls.
-
- "1,1" is the bottom left square of the user's screen. This aligns perfectly with the turf grid.
- "1:2,3:4" is the square (1,3) with pixel offsets (+2, +4); slightly right and slightly above the turf grid.
- Pixel offsets are used so you don't perfectly hide the turf under them, that would be crappy.
-
- In addition, the keywords NORTH, SOUTH, EAST, WEST and CENTER can be used to represent their respective
- screen borders. NORTH-1, for example, is the row just below the upper edge. Useful if you want your
- UI to scale with screen size.
-
- The size of the user's screen is defined by client.view (indirectly by world.view), in our case "15x15".
- Therefore, the top right corner (except during admin shenanigans) is at "15,15"
-*/
-
-//Lower left, persistent menu
-#define ui_inventory "WEST:6,SOUTH:5"
-
-//Middle left indicators
-#define ui_lingchemdisplay "WEST,CENTER-1:15"
-#define ui_lingstingdisplay "WEST:6,CENTER-3:11"
-#define ui_crafting "12:-10,1:5"
-#define ui_building "12:-10,1:21"
-#define ui_language_menu "11:6,2:-11"
-
-#define ui_devilsouldisplay "WEST:6,CENTER-1:15"
-
-//Lower center, persistent menu
-#define ui_sstore1 "CENTER-5:10,SOUTH:5"
-#define ui_id "CENTER-4:12,SOUTH:5"
-#define ui_belt "CENTER-3:14,SOUTH:5"
-#define ui_back "CENTER-2:14,SOUTH:5"
-
-/proc/ui_hand_position(i) //values based on old hand ui positions (CENTER:-/+16,SOUTH:5)
- var/x_off = -(!(i % 2))
- var/y_off = round((i-1) / 2)
- return"CENTER+[x_off]:16,SOUTH+[y_off]:5"
-
-/proc/ui_equip_position(mob/M)
- var/y_off = round((M.held_items.len-1) / 2) //values based on old equip ui position (CENTER: +/-16,SOUTH+1:5)
- return "CENTER:-16,SOUTH+[y_off+1]:5"
-
-/proc/ui_swaphand_position(mob/M, which = 1) //values based on old swaphand ui positions (CENTER: +/-16,SOUTH+1:5)
- var/x_off = which == 1 ? -1 : 0
- var/y_off = round((M.held_items.len-1) / 2)
- return "CENTER+[x_off]:16,SOUTH+[y_off+1]:5"
-
-#define ui_storage1 "CENTER+1:18,SOUTH:5"
-#define ui_storage2 "CENTER+2:20,SOUTH:5"
-
-#define ui_borg_sensor "CENTER-3:16, SOUTH:5" //borgs
-#define ui_borg_lamp "CENTER-4:16, SOUTH:5" //borgs
-#define ui_borg_thrusters "CENTER-5:16, SOUTH:5" //borgs
-#define ui_inv1 "CENTER-2:16,SOUTH:5" //borgs
-#define ui_inv2 "CENTER-1 :16,SOUTH:5" //borgs
-#define ui_inv3 "CENTER :16,SOUTH:5" //borgs
-#define ui_borg_module "CENTER+1:16,SOUTH:5" //borgs
-#define ui_borg_store "CENTER+2:16,SOUTH:5" //borgs
-#define ui_borg_camera "CENTER+3:21,SOUTH:5" //borgs
-#define ui_borg_album "CENTER+4:21,SOUTH:5" //borgs
-#define ui_borg_language_menu "CENTER+4:21,SOUTH+1:5" //borgs
-
-#define ui_monkey_head "CENTER-5:13,SOUTH:5" //monkey
-#define ui_monkey_mask "CENTER-4:14,SOUTH:5" //monkey
-#define ui_monkey_neck "CENTER-3:15,SOUTH:5" //monkey
-#define ui_monkey_back "CENTER-2:16,SOUTH:5" //monkey
-
-#define ui_alien_storage_l "CENTER-2:14,SOUTH:5"//alien
-#define ui_alien_storage_r "CENTER+1:18,SOUTH:5"//alien
-#define ui_alien_language_menu "EAST-3:26,SOUTH:5" //alien
-
-#define ui_drone_drop "CENTER+1:18,SOUTH:5" //maintenance drones
-#define ui_drone_pull "CENTER+2:2,SOUTH:5" //maintenance drones
-#define ui_drone_storage "CENTER-2:14,SOUTH:5" //maintenance drones
-#define ui_drone_head "CENTER-3:14,SOUTH:5" //maintenance drones
-
-//Lower right, persistent menu
-#define ui_drop_throw "EAST-1:28,SOUTH+1:7"
-#define ui_pull_resist "EAST-2:26,SOUTH+1:7"
-#define ui_movi "EAST-2:26,SOUTH:5"
-#define ui_acti "EAST-3:24,SOUTH:5"
-#define ui_zonesel "EAST-1:28,SOUTH:5"
-#define ui_acti_alt "EAST-1:28,SOUTH:5" //alternative intent switcher for when the interface is hidden (F12)
-
-#define ui_borg_pull "EAST-2:26,SOUTH+1:7"
-#define ui_borg_radio "EAST-1:28,SOUTH+1:7"
-#define ui_borg_intents "EAST-2:26,SOUTH:5"
-
-
-//Upper-middle right (alerts)
-#define ui_alert1 "EAST-1:28,CENTER+5:27"
-#define ui_alert2 "EAST-1:28,CENTER+4:25"
-#define ui_alert3 "EAST-1:28,CENTER+3:23"
-#define ui_alert4 "EAST-1:28,CENTER+2:21"
-#define ui_alert5 "EAST-1:28,CENTER+1:19"
-
-
-//Middle right (status indicators)
-#define ui_healthdoll "EAST-1:28,CENTER-2:13"
-#define ui_health "EAST-1:28,CENTER-1:15"
-#define ui_internal "EAST-1:28,CENTER:17"
-
-//borgs
-#define ui_borg_health "EAST-1:28,CENTER-1:15" //borgs have the health display where humans have the pressure damage indicator.
-
-//aliens
-#define ui_alien_health "EAST,CENTER-1:15" //aliens have the health display where humans have the pressure damage indicator.
-#define ui_alienplasmadisplay "EAST,CENTER-2:15"
-#define ui_alien_queen_finder "EAST,CENTER-3:15"
-
-//constructs
-#define ui_construct_pull "EAST,CENTER-2:15"
-#define ui_construct_health "EAST,CENTER:15" //same as borgs and humans
-
-// AI
-
-#define ui_ai_core "SOUTH:6,WEST"
-#define ui_ai_camera_list "SOUTH:6,WEST+1"
-#define ui_ai_track_with_camera "SOUTH:6,WEST+2"
-#define ui_ai_camera_light "SOUTH:6,WEST+3"
-#define ui_ai_crew_monitor "SOUTH:6,WEST+4"
-#define ui_ai_crew_manifest "SOUTH:6,WEST+5"
-#define ui_ai_alerts "SOUTH:6,WEST+6"
-#define ui_ai_announcement "SOUTH:6,WEST+7"
-#define ui_ai_shuttle "SOUTH:6,WEST+8"
-#define ui_ai_state_laws "SOUTH:6,WEST+9"
-#define ui_ai_pda_send "SOUTH:6,WEST+10"
-#define ui_ai_pda_log "SOUTH:6,WEST+11"
-#define ui_ai_take_picture "SOUTH:6,WEST+12"
-#define ui_ai_view_images "SOUTH:6,WEST+13"
-#define ui_ai_sensor "SOUTH:6,WEST+14"
-
-//Pop-up inventory
-#define ui_shoes "WEST+1:8,SOUTH:5"
-
-#define ui_iclothing "WEST:6,SOUTH+1:7"
-#define ui_oclothing "WEST+1:8,SOUTH+1:7"
-#define ui_gloves "WEST+2:10,SOUTH+1:7"
-
-#define ui_glasses "WEST:6,SOUTH+3:11"
-#define ui_mask "WEST+1:8,SOUTH+2:9"
-#define ui_ears "WEST+2:10,SOUTH+2:9"
-#define ui_neck "WEST:6,SOUTH+2:9"
-#define ui_head "WEST+1:8,SOUTH+3:11"
-
-//Ghosts
-
-#define ui_ghost_jumptomob "SOUTH:6,CENTER-2:24"
-#define ui_ghost_orbit "SOUTH:6,CENTER-1:24"
-#define ui_ghost_reenter_corpse "SOUTH:6,CENTER:24"
-#define ui_ghost_teleport "SOUTH:6,CENTER+1:24"
-#define ui_ghost_pai "SOUTH: 6, CENTER+2:24"
-
-//Hand of God, god
-
-#define ui_deityhealth "EAST-1:28,CENTER-2:13"
-#define ui_deitypower "EAST-1:28,CENTER-1:15"
-#define ui_deityfollowers "EAST-1:28,CENTER:17"
+/*
+ These defines specificy screen locations. For more information, see the byond documentation on the screen_loc var.
+
+ The short version:
+
+ Everything is encoded as strings because apparently that's how Byond rolls.
+
+ "1,1" is the bottom left square of the user's screen. This aligns perfectly with the turf grid.
+ "1:2,3:4" is the square (1,3) with pixel offsets (+2, +4); slightly right and slightly above the turf grid.
+ Pixel offsets are used so you don't perfectly hide the turf under them, that would be crappy.
+
+ In addition, the keywords NORTH, SOUTH, EAST, WEST and CENTER can be used to represent their respective
+ screen borders. NORTH-1, for example, is the row just below the upper edge. Useful if you want your
+ UI to scale with screen size.
+
+ The size of the user's screen is defined by client.view (indirectly by world.view), in our case "15x15".
+ Therefore, the top right corner (except during admin shenanigans) is at "15,15"
+*/
+
+//Lower left, persistent menu
+#define ui_inventory "WEST:6,SOUTH:5"
+
+//Middle left indicators
+#define ui_lingchemdisplay "WEST,CENTER-1:15"
+#define ui_lingstingdisplay "WEST:6,CENTER-3:11"
+#define ui_crafting "12:-10,1:5"
+#define ui_building "12:-10,1:21"
+#define ui_language_menu "11:6,2:-11"
+
+#define ui_devilsouldisplay "WEST:6,CENTER-1:15"
+
+//Lower center, persistent menu
+#define ui_sstore1 "CENTER-5:10,SOUTH:5"
+#define ui_id "CENTER-4:12,SOUTH:5"
+#define ui_belt "CENTER-3:14,SOUTH:5"
+#define ui_back "CENTER-2:14,SOUTH:5"
+
+/proc/ui_hand_position(i) //values based on old hand ui positions (CENTER:-/+16,SOUTH:5)
+ var/x_off = -(!(i % 2))
+ var/y_off = round((i-1) / 2)
+ return"CENTER+[x_off]:16,SOUTH+[y_off]:5"
+
+/proc/ui_equip_position(mob/M)
+ var/y_off = round((M.held_items.len-1) / 2) //values based on old equip ui position (CENTER: +/-16,SOUTH+1:5)
+ return "CENTER:-16,SOUTH+[y_off+1]:5"
+
+/proc/ui_swaphand_position(mob/M, which = 1) //values based on old swaphand ui positions (CENTER: +/-16,SOUTH+1:5)
+ var/x_off = which == 1 ? -1 : 0
+ var/y_off = round((M.held_items.len-1) / 2)
+ return "CENTER+[x_off]:16,SOUTH+[y_off+1]:5"
+
+#define ui_storage1 "CENTER+1:18,SOUTH:5"
+#define ui_storage2 "CENTER+2:20,SOUTH:5"
+
+#define ui_borg_sensor "CENTER-3:16, SOUTH:5" //borgs
+#define ui_borg_lamp "CENTER-4:16, SOUTH:5" //borgs
+#define ui_borg_thrusters "CENTER-5:16, SOUTH:5" //borgs
+#define ui_inv1 "CENTER-2:16,SOUTH:5" //borgs
+#define ui_inv2 "CENTER-1 :16,SOUTH:5" //borgs
+#define ui_inv3 "CENTER :16,SOUTH:5" //borgs
+#define ui_borg_module "CENTER+1:16,SOUTH:5" //borgs
+#define ui_borg_store "CENTER+2:16,SOUTH:5" //borgs
+#define ui_borg_camera "CENTER+3:21,SOUTH:5" //borgs
+#define ui_borg_album "CENTER+4:21,SOUTH:5" //borgs
+#define ui_borg_language_menu "CENTER+4:21,SOUTH+1:5" //borgs
+
+#define ui_monkey_head "CENTER-5:13,SOUTH:5" //monkey
+#define ui_monkey_mask "CENTER-4:14,SOUTH:5" //monkey
+#define ui_monkey_neck "CENTER-3:15,SOUTH:5" //monkey
+#define ui_monkey_back "CENTER-2:16,SOUTH:5" //monkey
+
+#define ui_alien_storage_l "CENTER-2:14,SOUTH:5"//alien
+#define ui_alien_storage_r "CENTER+1:18,SOUTH:5"//alien
+#define ui_alien_language_menu "EAST-3:26,SOUTH:5" //alien
+
+#define ui_drone_drop "CENTER+1:18,SOUTH:5" //maintenance drones
+#define ui_drone_pull "CENTER+2:2,SOUTH:5" //maintenance drones
+#define ui_drone_storage "CENTER-2:14,SOUTH:5" //maintenance drones
+#define ui_drone_head "CENTER-3:14,SOUTH:5" //maintenance drones
+
+//Lower right, persistent menu
+#define ui_drop_throw "EAST-1:28,SOUTH+1:7"
+#define ui_pull_resist "EAST-2:26,SOUTH+1:7"
+#define ui_movi "EAST-2:26,SOUTH:5"
+#define ui_acti "EAST-3:24,SOUTH:5"
+#define ui_zonesel "EAST-1:28,SOUTH:5"
+#define ui_acti_alt "EAST-1:28,SOUTH:5" //alternative intent switcher for when the interface is hidden (F12)
+
+#define ui_borg_pull "EAST-2:26,SOUTH+1:7"
+#define ui_borg_radio "EAST-1:28,SOUTH+1:7"
+#define ui_borg_intents "EAST-2:26,SOUTH:5"
+
+
+//Upper-middle right (alerts)
+#define ui_alert1 "EAST-1:28,CENTER+5:27"
+#define ui_alert2 "EAST-1:28,CENTER+4:25"
+#define ui_alert3 "EAST-1:28,CENTER+3:23"
+#define ui_alert4 "EAST-1:28,CENTER+2:21"
+#define ui_alert5 "EAST-1:28,CENTER+1:19"
+
+
+//Middle right (status indicators)
+#define ui_healthdoll "EAST-1:28,CENTER-2:13"
+#define ui_health "EAST-1:28,CENTER-1:15"
+#define ui_internal "EAST-1:28,CENTER:17"
+
+//borgs
+#define ui_borg_health "EAST-1:28,CENTER-1:15" //borgs have the health display where humans have the pressure damage indicator.
+
+//aliens
+#define ui_alien_health "EAST,CENTER-1:15" //aliens have the health display where humans have the pressure damage indicator.
+#define ui_alienplasmadisplay "EAST,CENTER-2:15"
+#define ui_alien_queen_finder "EAST,CENTER-3:15"
+
+//constructs
+#define ui_construct_pull "EAST,CENTER-2:15"
+#define ui_construct_health "EAST,CENTER:15" //same as borgs and humans
+
+// AI
+
+#define ui_ai_core "SOUTH:6,WEST"
+#define ui_ai_camera_list "SOUTH:6,WEST+1"
+#define ui_ai_track_with_camera "SOUTH:6,WEST+2"
+#define ui_ai_camera_light "SOUTH:6,WEST+3"
+#define ui_ai_crew_monitor "SOUTH:6,WEST+4"
+#define ui_ai_crew_manifest "SOUTH:6,WEST+5"
+#define ui_ai_alerts "SOUTH:6,WEST+6"
+#define ui_ai_announcement "SOUTH:6,WEST+7"
+#define ui_ai_shuttle "SOUTH:6,WEST+8"
+#define ui_ai_state_laws "SOUTH:6,WEST+9"
+#define ui_ai_pda_send "SOUTH:6,WEST+10"
+#define ui_ai_pda_log "SOUTH:6,WEST+11"
+#define ui_ai_take_picture "SOUTH:6,WEST+12"
+#define ui_ai_view_images "SOUTH:6,WEST+13"
+#define ui_ai_sensor "SOUTH:6,WEST+14"
+
+//Pop-up inventory
+#define ui_shoes "WEST+1:8,SOUTH:5"
+
+#define ui_iclothing "WEST:6,SOUTH+1:7"
+#define ui_oclothing "WEST+1:8,SOUTH+1:7"
+#define ui_gloves "WEST+2:10,SOUTH+1:7"
+
+#define ui_glasses "WEST:6,SOUTH+3:11"
+#define ui_mask "WEST+1:8,SOUTH+2:9"
+#define ui_ears "WEST+2:10,SOUTH+2:9"
+#define ui_neck "WEST:6,SOUTH+2:9"
+#define ui_head "WEST+1:8,SOUTH+3:11"
+
+//Ghosts
+
+#define ui_ghost_jumptomob "SOUTH:6,CENTER-2:24"
+#define ui_ghost_orbit "SOUTH:6,CENTER-1:24"
+#define ui_ghost_reenter_corpse "SOUTH:6,CENTER:24"
+#define ui_ghost_teleport "SOUTH:6,CENTER+1:24"
+#define ui_ghost_pai "SOUTH: 6, CENTER+2:24"
+
+//Hand of God, god
+
+#define ui_deityhealth "EAST-1:28,CENTER-2:13"
+#define ui_deitypower "EAST-1:28,CENTER-1:15"
+#define ui_deityfollowers "EAST-1:28,CENTER:17"
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
index 30db96c79f..1bb3ba5223 100644
--- a/code/_onclick/hud/hud.dm
+++ b/code/_onclick/hud/hud.dm
@@ -1,270 +1,270 @@
-/*
- The hud datum
- Used to show and hide huds for all the different mob types,
- including inventories and item quick actions.
-*/
-
-/datum/hud
- var/mob/mymob
-
- var/hud_shown = 1 //Used for the HUD toggle (F12)
- var/hud_version = 1 //Current displayed version of the HUD
- var/inventory_shown = 0 //Equipped item inventory
- var/show_intent_icons = 0
- var/hotkey_ui_hidden = 0 //This is to hide the buttons that can be used via hotkeys. (hotkeybuttons list of buttons)
-
- var/obj/screen/ling/chems/lingchemdisplay
- var/obj/screen/ling/sting/lingstingdisplay
-
- var/obj/screen/blobpwrdisplay
-
- var/obj/screen/alien_plasma_display
- var/obj/screen/alien_queen_finder
-
- var/obj/screen/devil/soul_counter/devilsouldisplay
-
- var/obj/screen/deity_power_display
- var/obj/screen/deity_follower_display
-
- var/obj/screen/nightvisionicon
- var/obj/screen/action_intent
- var/obj/screen/zone_select
- var/obj/screen/pull_icon
- var/obj/screen/throw_icon
- var/obj/screen/module_store_icon
-
- var/list/static_inventory = list() //the screen objects which are static
- var/list/toggleable_inventory = list() //the screen objects which can be hidden
- var/list/obj/screen/hotkeybuttons = list() //the buttons that can be used via hotkeys
- var/list/infodisplay = list() //the screen objects that display mob info (health, alien plasma, etc...)
- var/list/screenoverlays = list() //the screen objects used as whole screen overlays (flash, damageoverlay, etc...)
- var/list/inv_slots[slots_amt] // /obj/screen/inventory objects, ordered by their slot ID.
- var/list/hand_slots // /obj/screen/inventory/hand objects, assoc list of "[held_index]" = object
- var/list/obj/screen/plane_master/plane_masters = list() // see "appearance_flags" in the ref, assoc list of "[plane]" = object
-
- var/obj/screen/movable/action_button/hide_toggle/hide_actions_toggle
- var/action_buttons_hidden = 0
-
- var/obj/screen/healths
- var/obj/screen/healthdoll
- var/obj/screen/internals
-
- var/ui_style_icon = 'icons/mob/screen_midnight.dmi'
-
-/datum/hud/New(mob/owner , ui_style = 'icons/mob/screen_midnight.dmi')
- mymob = owner
-
- ui_style_icon = ui_style
-
- hide_actions_toggle = new
- hide_actions_toggle.InitialiseIcon(src)
-
- hand_slots = list()
-
- for(var/mytype in subtypesof(/obj/screen/plane_master))
- var/obj/screen/plane_master/instance = new mytype()
- plane_masters["[instance.plane]"] = instance
- instance.backdrop(mymob)
-
-/datum/hud/Destroy()
- if(mymob.hud_used == src)
- mymob.hud_used = null
-
- qdel(hide_actions_toggle)
- hide_actions_toggle = null
-
- qdel(module_store_icon)
- module_store_icon = null
-
- if(static_inventory.len)
- for(var/thing in static_inventory)
- qdel(thing)
- static_inventory.Cut()
-
- inv_slots.Cut()
- action_intent = null
- zone_select = null
- pull_icon = null
-
- if(toggleable_inventory.len)
- for(var/thing in toggleable_inventory)
- qdel(thing)
- toggleable_inventory.Cut()
-
- if(hotkeybuttons.len)
- for(var/thing in hotkeybuttons)
- qdel(thing)
- hotkeybuttons.Cut()
-
- throw_icon = null
-
- if(infodisplay.len)
- for(var/thing in infodisplay)
- qdel(thing)
- infodisplay.Cut()
-
- healths = null
- healthdoll = null
- internals = null
- lingchemdisplay = null
- devilsouldisplay = null
- lingstingdisplay = null
- blobpwrdisplay = null
- alien_plasma_display = null
- alien_queen_finder = null
- deity_power_display = null
- deity_follower_display = null
- nightvisionicon = null
-
- if(plane_masters.len)
- for(var/thing in plane_masters)
- qdel(plane_masters[thing])
- plane_masters.Cut()
-
- if(screenoverlays.len)
- for(var/thing in screenoverlays)
- qdel(thing)
- screenoverlays.Cut()
- mymob = null
-
- return ..()
-
-/mob/proc/create_mob_hud()
- if(client && !hud_used)
- hud_used = new /datum/hud(src)
- update_sight()
-
-//Version denotes which style should be displayed. blank or 0 means "next version"
-/datum/hud/proc/show_hud(version = 0,mob/viewmob)
- if(!ismob(mymob))
- return 0
- var/mob/screenmob = viewmob || mymob
- if(!screenmob.client)
- return 0
-
- screenmob.client.screen = list()
-
- var/display_hud_version = version
- if(!display_hud_version) //If 0 or blank, display the next hud version
- display_hud_version = hud_version + 1
- if(display_hud_version > HUD_VERSIONS) //If the requested version number is greater than the available versions, reset back to the first version
- display_hud_version = 1
-
- switch(display_hud_version)
- if(HUD_STYLE_STANDARD) //Default HUD
- hud_shown = 1 //Governs behavior of other procs
- if(static_inventory.len)
- screenmob.client.screen += static_inventory
- if(toggleable_inventory.len && screenmob.hud_used && screenmob.hud_used.inventory_shown)
- screenmob.client.screen += toggleable_inventory
- if(hotkeybuttons.len && !hotkey_ui_hidden)
- screenmob.client.screen += hotkeybuttons
- if(infodisplay.len)
- screenmob.client.screen += infodisplay
-
- screenmob.client.screen += hide_actions_toggle
-
- if(action_intent)
- action_intent.screen_loc = initial(action_intent.screen_loc) //Restore intent selection to the original position
-
- if(HUD_STYLE_REDUCED) //Reduced HUD
- hud_shown = 0 //Governs behavior of other procs
- if(static_inventory.len)
- screenmob.client.screen -= static_inventory
- if(toggleable_inventory.len)
- screenmob.client.screen -= toggleable_inventory
- if(hotkeybuttons.len)
- screenmob.client.screen -= hotkeybuttons
- if(infodisplay.len)
- screenmob.client.screen += infodisplay
-
- //These ones are a part of 'static_inventory', 'toggleable_inventory' or 'hotkeybuttons' but we want them to stay
- for(var/h in hand_slots)
- var/obj/screen/hand = hand_slots[h]
- if(hand)
- screenmob.client.screen += hand
- if(action_intent)
- screenmob.client.screen += action_intent //we want the intent switcher visible
- action_intent.screen_loc = ui_acti_alt //move this to the alternative position, where zone_select usually is.
-
- if(HUD_STYLE_NOHUD) //No HUD
- hud_shown = 0 //Governs behavior of other procs
- if(static_inventory.len)
- screenmob.client.screen -= static_inventory
- if(toggleable_inventory.len)
- screenmob.client.screen -= toggleable_inventory
- if(hotkeybuttons.len)
- screenmob.client.screen -= hotkeybuttons
- if(infodisplay.len)
- screenmob.client.screen -= infodisplay
-
- for(var/thing in plane_masters)
- screenmob.client.screen += plane_masters[thing]
-
- hud_version = display_hud_version
- persistent_inventory_update(screenmob)
- mymob.update_action_buttons(1)
- reorganize_alerts()
- mymob.reload_fullscreen()
- update_parallax_pref(screenmob)
-
-/datum/hud/human/show_hud(version = 0,mob/viewmob)
- ..()
- hidden_inventory_update(viewmob)
-
-/datum/hud/robot/show_hud(version = 0, mob/viewmob)
- ..()
- update_robot_modules_display()
-
-/datum/hud/proc/hidden_inventory_update()
- return
-
-/datum/hud/proc/persistent_inventory_update(mob/viewer)
- if(!mymob)
- return
-
-//Triggered when F12 is pressed (Unless someone changed something in the DMF)
-/mob/verb/button_pressed_F12()
- set name = "F12"
- set hidden = 1
-
- if(hud_used && client)
- hud_used.show_hud() //Shows the next hud preset
- to_chat(usr, "Switched HUD mode. Press F12 to toggle.")
- else
- to_chat(usr, "This mob type does not use a HUD.")
-
-
-//(re)builds the hand ui slots, throwing away old ones
-//not really worth jugglying existing ones so we just scrap+rebuild
-//9/10 this is only called once per mob and only for 2 hands
-/datum/hud/proc/build_hand_slots(ui_style = 'icons/mob/screen_midnight.dmi')
- for(var/h in hand_slots)
- var/obj/screen/inventory/hand/H = hand_slots[h]
- if(H)
- static_inventory -= H
- hand_slots = list()
- var/obj/screen/inventory/hand/hand_box
- for(var/i in 1 to mymob.held_items.len)
- hand_box = new /obj/screen/inventory/hand()
- hand_box.name = mymob.get_held_index_name(i)
- hand_box.icon = ui_style
- hand_box.icon_state = "hand_[mymob.held_index_to_dir(i)]"
- hand_box.screen_loc = ui_hand_position(i)
- hand_box.held_index = i
- hand_slots["[i]"] = hand_box
- hand_box.hud = src
- static_inventory += hand_box
- hand_box.update_icon()
-
- var/i = 1
- for(var/obj/screen/swap_hand/SH in static_inventory)
- SH.screen_loc = ui_swaphand_position(mymob,!(i % 2) ? 2: 1)
- i++
- for(var/obj/screen/human/equip/E in static_inventory)
- E.screen_loc = ui_equip_position(mymob)
- if(mymob.hud_used)
- show_hud(HUD_STYLE_STANDARD,mymob)
-
-/datum/hud/proc/update_locked_slots()
+/*
+ The hud datum
+ Used to show and hide huds for all the different mob types,
+ including inventories and item quick actions.
+*/
+
+/datum/hud
+ var/mob/mymob
+
+ var/hud_shown = 1 //Used for the HUD toggle (F12)
+ var/hud_version = 1 //Current displayed version of the HUD
+ var/inventory_shown = 0 //Equipped item inventory
+ var/show_intent_icons = 0
+ var/hotkey_ui_hidden = 0 //This is to hide the buttons that can be used via hotkeys. (hotkeybuttons list of buttons)
+
+ var/obj/screen/ling/chems/lingchemdisplay
+ var/obj/screen/ling/sting/lingstingdisplay
+
+ var/obj/screen/blobpwrdisplay
+
+ var/obj/screen/alien_plasma_display
+ var/obj/screen/alien_queen_finder
+
+ var/obj/screen/devil/soul_counter/devilsouldisplay
+
+ var/obj/screen/deity_power_display
+ var/obj/screen/deity_follower_display
+
+ var/obj/screen/nightvisionicon
+ var/obj/screen/action_intent
+ var/obj/screen/zone_select
+ var/obj/screen/pull_icon
+ var/obj/screen/throw_icon
+ var/obj/screen/module_store_icon
+
+ var/list/static_inventory = list() //the screen objects which are static
+ var/list/toggleable_inventory = list() //the screen objects which can be hidden
+ var/list/obj/screen/hotkeybuttons = list() //the buttons that can be used via hotkeys
+ var/list/infodisplay = list() //the screen objects that display mob info (health, alien plasma, etc...)
+ var/list/screenoverlays = list() //the screen objects used as whole screen overlays (flash, damageoverlay, etc...)
+ var/list/inv_slots[slots_amt] // /obj/screen/inventory objects, ordered by their slot ID.
+ var/list/hand_slots // /obj/screen/inventory/hand objects, assoc list of "[held_index]" = object
+ var/list/obj/screen/plane_master/plane_masters = list() // see "appearance_flags" in the ref, assoc list of "[plane]" = object
+
+ var/obj/screen/movable/action_button/hide_toggle/hide_actions_toggle
+ var/action_buttons_hidden = 0
+
+ var/obj/screen/healths
+ var/obj/screen/healthdoll
+ var/obj/screen/internals
+
+ var/ui_style_icon = 'icons/mob/screen_midnight.dmi'
+
+/datum/hud/New(mob/owner , ui_style = 'icons/mob/screen_midnight.dmi')
+ mymob = owner
+
+ ui_style_icon = ui_style
+
+ hide_actions_toggle = new
+ hide_actions_toggle.InitialiseIcon(src)
+
+ hand_slots = list()
+
+ for(var/mytype in subtypesof(/obj/screen/plane_master))
+ var/obj/screen/plane_master/instance = new mytype()
+ plane_masters["[instance.plane]"] = instance
+ instance.backdrop(mymob)
+
+/datum/hud/Destroy()
+ if(mymob.hud_used == src)
+ mymob.hud_used = null
+
+ qdel(hide_actions_toggle)
+ hide_actions_toggle = null
+
+ qdel(module_store_icon)
+ module_store_icon = null
+
+ if(static_inventory.len)
+ for(var/thing in static_inventory)
+ qdel(thing)
+ static_inventory.Cut()
+
+ inv_slots.Cut()
+ action_intent = null
+ zone_select = null
+ pull_icon = null
+
+ if(toggleable_inventory.len)
+ for(var/thing in toggleable_inventory)
+ qdel(thing)
+ toggleable_inventory.Cut()
+
+ if(hotkeybuttons.len)
+ for(var/thing in hotkeybuttons)
+ qdel(thing)
+ hotkeybuttons.Cut()
+
+ throw_icon = null
+
+ if(infodisplay.len)
+ for(var/thing in infodisplay)
+ qdel(thing)
+ infodisplay.Cut()
+
+ healths = null
+ healthdoll = null
+ internals = null
+ lingchemdisplay = null
+ devilsouldisplay = null
+ lingstingdisplay = null
+ blobpwrdisplay = null
+ alien_plasma_display = null
+ alien_queen_finder = null
+ deity_power_display = null
+ deity_follower_display = null
+ nightvisionicon = null
+
+ if(plane_masters.len)
+ for(var/thing in plane_masters)
+ qdel(plane_masters[thing])
+ plane_masters.Cut()
+
+ if(screenoverlays.len)
+ for(var/thing in screenoverlays)
+ qdel(thing)
+ screenoverlays.Cut()
+ mymob = null
+
+ return ..()
+
+/mob/proc/create_mob_hud()
+ if(client && !hud_used)
+ hud_used = new /datum/hud(src)
+ update_sight()
+
+//Version denotes which style should be displayed. blank or 0 means "next version"
+/datum/hud/proc/show_hud(version = 0,mob/viewmob)
+ if(!ismob(mymob))
+ return 0
+ var/mob/screenmob = viewmob || mymob
+ if(!screenmob.client)
+ return 0
+
+ screenmob.client.screen = list()
+
+ var/display_hud_version = version
+ if(!display_hud_version) //If 0 or blank, display the next hud version
+ display_hud_version = hud_version + 1
+ if(display_hud_version > HUD_VERSIONS) //If the requested version number is greater than the available versions, reset back to the first version
+ display_hud_version = 1
+
+ switch(display_hud_version)
+ if(HUD_STYLE_STANDARD) //Default HUD
+ hud_shown = 1 //Governs behavior of other procs
+ if(static_inventory.len)
+ screenmob.client.screen += static_inventory
+ if(toggleable_inventory.len && screenmob.hud_used && screenmob.hud_used.inventory_shown)
+ screenmob.client.screen += toggleable_inventory
+ if(hotkeybuttons.len && !hotkey_ui_hidden)
+ screenmob.client.screen += hotkeybuttons
+ if(infodisplay.len)
+ screenmob.client.screen += infodisplay
+
+ screenmob.client.screen += hide_actions_toggle
+
+ if(action_intent)
+ action_intent.screen_loc = initial(action_intent.screen_loc) //Restore intent selection to the original position
+
+ if(HUD_STYLE_REDUCED) //Reduced HUD
+ hud_shown = 0 //Governs behavior of other procs
+ if(static_inventory.len)
+ screenmob.client.screen -= static_inventory
+ if(toggleable_inventory.len)
+ screenmob.client.screen -= toggleable_inventory
+ if(hotkeybuttons.len)
+ screenmob.client.screen -= hotkeybuttons
+ if(infodisplay.len)
+ screenmob.client.screen += infodisplay
+
+ //These ones are a part of 'static_inventory', 'toggleable_inventory' or 'hotkeybuttons' but we want them to stay
+ for(var/h in hand_slots)
+ var/obj/screen/hand = hand_slots[h]
+ if(hand)
+ screenmob.client.screen += hand
+ if(action_intent)
+ screenmob.client.screen += action_intent //we want the intent switcher visible
+ action_intent.screen_loc = ui_acti_alt //move this to the alternative position, where zone_select usually is.
+
+ if(HUD_STYLE_NOHUD) //No HUD
+ hud_shown = 0 //Governs behavior of other procs
+ if(static_inventory.len)
+ screenmob.client.screen -= static_inventory
+ if(toggleable_inventory.len)
+ screenmob.client.screen -= toggleable_inventory
+ if(hotkeybuttons.len)
+ screenmob.client.screen -= hotkeybuttons
+ if(infodisplay.len)
+ screenmob.client.screen -= infodisplay
+
+ for(var/thing in plane_masters)
+ screenmob.client.screen += plane_masters[thing]
+
+ hud_version = display_hud_version
+ persistent_inventory_update(screenmob)
+ mymob.update_action_buttons(1)
+ reorganize_alerts()
+ mymob.reload_fullscreen()
+ update_parallax_pref(screenmob)
+
+/datum/hud/human/show_hud(version = 0,mob/viewmob)
+ ..()
+ hidden_inventory_update(viewmob)
+
+/datum/hud/robot/show_hud(version = 0, mob/viewmob)
+ ..()
+ update_robot_modules_display()
+
+/datum/hud/proc/hidden_inventory_update()
+ return
+
+/datum/hud/proc/persistent_inventory_update(mob/viewer)
+ if(!mymob)
+ return
+
+//Triggered when F12 is pressed (Unless someone changed something in the DMF)
+/mob/verb/button_pressed_F12()
+ set name = "F12"
+ set hidden = 1
+
+ if(hud_used && client)
+ hud_used.show_hud() //Shows the next hud preset
+ to_chat(usr, "Switched HUD mode. Press F12 to toggle.")
+ else
+ to_chat(usr, "This mob type does not use a HUD.")
+
+
+//(re)builds the hand ui slots, throwing away old ones
+//not really worth jugglying existing ones so we just scrap+rebuild
+//9/10 this is only called once per mob and only for 2 hands
+/datum/hud/proc/build_hand_slots(ui_style = 'icons/mob/screen_midnight.dmi')
+ for(var/h in hand_slots)
+ var/obj/screen/inventory/hand/H = hand_slots[h]
+ if(H)
+ static_inventory -= H
+ hand_slots = list()
+ var/obj/screen/inventory/hand/hand_box
+ for(var/i in 1 to mymob.held_items.len)
+ hand_box = new /obj/screen/inventory/hand()
+ hand_box.name = mymob.get_held_index_name(i)
+ hand_box.icon = ui_style
+ hand_box.icon_state = "hand_[mymob.held_index_to_dir(i)]"
+ hand_box.screen_loc = ui_hand_position(i)
+ hand_box.held_index = i
+ hand_slots["[i]"] = hand_box
+ hand_box.hud = src
+ static_inventory += hand_box
+ hand_box.update_icon()
+
+ var/i = 1
+ for(var/obj/screen/swap_hand/SH in static_inventory)
+ SH.screen_loc = ui_swaphand_position(mymob,!(i % 2) ? 2: 1)
+ i++
+ for(var/obj/screen/human/equip/E in static_inventory)
+ E.screen_loc = ui_equip_position(mymob)
+ if(mymob.hud_used)
+ show_hud(HUD_STYLE_STANDARD,mymob)
+
+/datum/hud/proc/update_locked_slots()
return
\ No newline at end of file
diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm
index e759b0c111..ecb13d8a9b 100644
--- a/code/_onclick/hud/human.dm
+++ b/code/_onclick/hud/human.dm
@@ -1,438 +1,438 @@
-/obj/screen/human
- icon = 'icons/mob/screen_midnight.dmi'
-
-/obj/screen/human/toggle
- name = "toggle"
- icon_state = "toggle"
-
-/obj/screen/human/toggle/Click()
-
- var/mob/targetmob = usr
-
- if(isobserver(usr))
- if(ishuman(usr.client.eye) && (usr.client.eye != usr))
- var/mob/M = usr.client.eye
- targetmob = M
-
- if(usr.hud_used.inventory_shown && targetmob.hud_used)
- usr.hud_used.inventory_shown = 0
- usr.client.screen -= targetmob.hud_used.toggleable_inventory
- else
- usr.hud_used.inventory_shown = 1
- usr.client.screen += targetmob.hud_used.toggleable_inventory
-
- targetmob.hud_used.hidden_inventory_update(usr)
-
-/obj/screen/human/equip
- name = "equip"
- icon_state = "act_equip"
-
-/obj/screen/human/equip/Click()
- if(istype(usr.loc,/obj/mecha)) // stops inventory actions in a mech
- return 1
- var/mob/living/carbon/human/H = usr
- H.quick_equip()
-
-/obj/screen/devil
- invisibility = INVISIBILITY_ABSTRACT
-
-/obj/screen/devil/soul_counter
- icon = 'icons/mob/screen_gen.dmi'
- name = "souls owned"
- icon_state = "Devil-6"
- screen_loc = ui_devilsouldisplay
-
-/obj/screen/devil/soul_counter/proc/update_counter(souls = 0)
- invisibility = 0
- maptext = "
[souls]
"
- switch(souls)
- if(0,null)
- icon_state = "Devil-1"
- if(1,2)
- icon_state = "Devil-2"
- if(3 to 5)
- icon_state = "Devil-3"
- if(6 to 8)
- icon_state = "Devil-4"
- if(9 to INFINITY)
- icon_state = "Devil-5"
- else
- icon_state = "Devil-6"
-
-/obj/screen/devil/soul_counter/proc/clear()
- invisibility = INVISIBILITY_ABSTRACT
-
-/obj/screen/ling
- invisibility = INVISIBILITY_ABSTRACT
-
-/obj/screen/ling/sting
- name = "current sting"
- screen_loc = ui_lingstingdisplay
-
-/obj/screen/ling/sting/Click()
- if(isobserver(usr))
- return
- var/mob/living/carbon/U = usr
- U.unset_sting()
-
-/obj/screen/ling/chems
- name = "chemical storage"
- icon_state = "power_display"
- screen_loc = ui_lingchemdisplay
-
-/mob/living/carbon/human/create_mob_hud()
- if(client && !hud_used)
- hud_used = new /datum/hud/human(src, ui_style2icon(client.prefs.UI_style))
-
-
-/datum/hud/human/New(mob/living/carbon/human/owner, ui_style = 'icons/mob/screen_midnight.dmi')
- ..()
- owner.overlay_fullscreen("see_through_darkness", /obj/screen/fullscreen/see_through_darkness)
-
- var/obj/screen/using
- var/obj/screen/inventory/inv_box
-
- using = new /obj/screen/craft
- using.icon = ui_style
- static_inventory += using
-
- using = new/obj/screen/language_menu
- using.icon = ui_style
- static_inventory += using
-
- using = new /obj/screen/area_creator
- using.icon = ui_style
- static_inventory += using
-
- action_intent = new /obj/screen/act_intent/segmented
- action_intent.icon_state = mymob.a_intent
- static_inventory += action_intent
-
- using = new /obj/screen/mov_intent
- using.icon = ui_style
- using.icon_state = (mymob.m_intent == MOVE_INTENT_RUN ? "running" : "walking")
- using.screen_loc = ui_movi
- static_inventory += using
-
- using = new /obj/screen/drop()
- using.icon = ui_style
- using.screen_loc = ui_drop_throw
- static_inventory += using
-
- inv_box = new /obj/screen/inventory()
- inv_box.name = "i_clothing"
- inv_box.icon = ui_style
- inv_box.slot_id = slot_w_uniform
- inv_box.icon_state = "uniform"
- inv_box.screen_loc = ui_iclothing
- toggleable_inventory += inv_box
-
- inv_box = new /obj/screen/inventory()
- inv_box.name = "o_clothing"
- inv_box.icon = ui_style
- inv_box.slot_id = slot_wear_suit
- inv_box.icon_state = "suit"
- inv_box.screen_loc = ui_oclothing
- toggleable_inventory += inv_box
-
- build_hand_slots(ui_style)
-
- using = new /obj/screen/swap_hand()
- using.icon = ui_style
- using.icon_state = "swap_1"
- using.screen_loc = ui_swaphand_position(owner,1)
- static_inventory += using
-
- using = new /obj/screen/swap_hand()
- using.icon = ui_style
- using.icon_state = "swap_2"
- using.screen_loc = ui_swaphand_position(owner,2)
- static_inventory += using
-
- inv_box = new /obj/screen/inventory()
- inv_box.name = "id"
- inv_box.icon = ui_style
- inv_box.icon_state = "id"
- inv_box.screen_loc = ui_id
- inv_box.slot_id = slot_wear_id
- static_inventory += inv_box
-
- inv_box = new /obj/screen/inventory()
- inv_box.name = "mask"
- inv_box.icon = ui_style
- inv_box.icon_state = "mask"
- inv_box.screen_loc = ui_mask
- inv_box.slot_id = slot_wear_mask
- toggleable_inventory += inv_box
-
- inv_box = new /obj/screen/inventory()
- inv_box.name = "neck"
- inv_box.icon = ui_style
- inv_box.icon_state = "neck"
- inv_box.screen_loc = ui_neck
- inv_box.slot_id = slot_neck
- toggleable_inventory += inv_box
-
- inv_box = new /obj/screen/inventory()
- inv_box.name = "back"
- inv_box.icon = ui_style
- inv_box.icon_state = "back"
- inv_box.screen_loc = ui_back
- inv_box.slot_id = slot_back
- static_inventory += inv_box
-
- inv_box = new /obj/screen/inventory()
- inv_box.name = "storage1"
- inv_box.icon = ui_style
- inv_box.icon_state = "pocket"
- inv_box.screen_loc = ui_storage1
- inv_box.slot_id = slot_l_store
- static_inventory += inv_box
-
- inv_box = new /obj/screen/inventory()
- inv_box.name = "storage2"
- inv_box.icon = ui_style
- inv_box.icon_state = "pocket"
- inv_box.screen_loc = ui_storage2
- inv_box.slot_id = slot_r_store
- static_inventory += inv_box
-
- inv_box = new /obj/screen/inventory()
- inv_box.name = "suit storage"
- inv_box.icon = ui_style
- inv_box.icon_state = "suit_storage"
- inv_box.screen_loc = ui_sstore1
- inv_box.slot_id = slot_s_store
- static_inventory += inv_box
-
- using = new /obj/screen/resist()
- using.icon = ui_style
- using.screen_loc = ui_pull_resist
- hotkeybuttons += using
-
- using = new /obj/screen/human/toggle()
- using.icon = ui_style
- using.screen_loc = ui_inventory
- static_inventory += using
-
- using = new /obj/screen/human/equip()
- using.icon = ui_style
- using.screen_loc = ui_equip_position(mymob)
- static_inventory += using
-
- inv_box = new /obj/screen/inventory()
- inv_box.name = "gloves"
- inv_box.icon = ui_style
- inv_box.icon_state = "gloves"
- inv_box.screen_loc = ui_gloves
- inv_box.slot_id = slot_gloves
- toggleable_inventory += inv_box
-
- inv_box = new /obj/screen/inventory()
- inv_box.name = "eyes"
- inv_box.icon = ui_style
- inv_box.icon_state = "glasses"
- inv_box.screen_loc = ui_glasses
- inv_box.slot_id = slot_glasses
- toggleable_inventory += inv_box
-
- inv_box = new /obj/screen/inventory()
- inv_box.name = "ears"
- inv_box.icon = ui_style
- inv_box.icon_state = "ears"
- inv_box.screen_loc = ui_ears
- inv_box.slot_id = slot_ears
- toggleable_inventory += inv_box
-
- inv_box = new /obj/screen/inventory()
- inv_box.name = "head"
- inv_box.icon = ui_style
- inv_box.icon_state = "head"
- inv_box.screen_loc = ui_head
- inv_box.slot_id = slot_head
- toggleable_inventory += inv_box
-
- inv_box = new /obj/screen/inventory()
- inv_box.name = "shoes"
- inv_box.icon = ui_style
- inv_box.icon_state = "shoes"
- inv_box.screen_loc = ui_shoes
- inv_box.slot_id = slot_shoes
- toggleable_inventory += inv_box
-
- inv_box = new /obj/screen/inventory()
- inv_box.name = "belt"
- inv_box.icon = ui_style
- inv_box.icon_state = "belt"
-// inv_box.icon_full = "template_small"
- inv_box.screen_loc = ui_belt
- inv_box.slot_id = slot_belt
- static_inventory += inv_box
-
- throw_icon = new /obj/screen/throw_catch()
- throw_icon.icon = ui_style
- throw_icon.screen_loc = ui_drop_throw
- hotkeybuttons += throw_icon
-
- internals = new /obj/screen/internals()
- infodisplay += internals
-
- healths = new /obj/screen/healths()
- infodisplay += healths
-
- //citadel code
- arousal = new /obj/screen/arousal()
- infodisplay += arousal
-
- healthdoll = new /obj/screen/healthdoll()
- infodisplay += healthdoll
-
- pull_icon = new /obj/screen/pull()
- pull_icon.icon = ui_style
- pull_icon.update_icon(mymob)
- pull_icon.screen_loc = ui_pull_resist
- static_inventory += pull_icon
-
- lingchemdisplay = new /obj/screen/ling/chems()
- infodisplay += lingchemdisplay
-
- lingstingdisplay = new /obj/screen/ling/sting()
- infodisplay += lingstingdisplay
-
- devilsouldisplay = new /obj/screen/devil/soul_counter
- infodisplay += devilsouldisplay
-
- zone_select = new /obj/screen/zone_sel()
- zone_select.icon = ui_style
- zone_select.update_icon(mymob)
- static_inventory += zone_select
-
- for(var/obj/screen/inventory/inv in (static_inventory + toggleable_inventory))
- if(inv.slot_id)
- inv.hud = src
- inv_slots[inv.slot_id] = inv
- inv.update_icon()
-
-/datum/hud/human/update_locked_slots()
- if(!mymob)
- return
- var/mob/living/carbon/human/H = mymob
- var/datum/species/S = H.dna.species
- for(var/obj/screen/inventory/inv in (static_inventory + toggleable_inventory))
- if(inv.slot_id)
- if(inv.slot_id in S.no_equip)
- inv.alpha = 128
- else
- inv.alpha = initial(inv.alpha)
-
-/datum/hud/human/hidden_inventory_update(mob/viewer)
- if(!mymob)
- return
- var/mob/living/carbon/human/H = mymob
-
- var/mob/screenmob = viewer || H
-
- if(screenmob.hud_used.inventory_shown && screenmob.hud_used.hud_shown)
- if(H.shoes)
- H.shoes.screen_loc = ui_shoes
- screenmob.client.screen += H.shoes
- if(H.gloves)
- H.gloves.screen_loc = ui_gloves
- screenmob.client.screen += H.gloves
- if(H.ears)
- H.ears.screen_loc = ui_ears
- screenmob.client.screen += H.ears
- if(H.glasses)
- H.glasses.screen_loc = ui_glasses
- screenmob.client.screen += H.glasses
- if(H.w_uniform)
- H.w_uniform.screen_loc = ui_iclothing
- screenmob.client.screen += H.w_uniform
- if(H.wear_suit)
- H.wear_suit.screen_loc = ui_oclothing
- screenmob.client.screen += H.wear_suit
- if(H.wear_mask)
- H.wear_mask.screen_loc = ui_mask
- screenmob.client.screen += H.wear_mask
- if(H.wear_neck)
- H.wear_neck.screen_loc = ui_neck
- screenmob.client.screen += H.wear_neck
- if(H.head)
- H.head.screen_loc = ui_head
- screenmob.client.screen += H.head
- else
- if(H.shoes) screenmob.client.screen -= H.shoes
- if(H.gloves) screenmob.client.screen -= H.gloves
- if(H.ears) screenmob.client.screen -= H.ears
- if(H.glasses) screenmob.client.screen -= H.glasses
- if(H.w_uniform) screenmob.client.screen -= H.w_uniform
- if(H.wear_suit) screenmob.client.screen -= H.wear_suit
- if(H.wear_mask) screenmob.client.screen -= H.wear_mask
- if(H.wear_neck) screenmob.client.screen -= H.wear_neck
- if(H.head) screenmob.client.screen -= H.head
-
-
-
-/datum/hud/human/persistent_inventory_update(mob/viewer)
- if(!mymob)
- return
- ..()
- var/mob/living/carbon/human/H = mymob
-
- var/mob/screenmob = viewer || H
-
- if(screenmob.hud_used)
- if(screenmob.hud_used.hud_shown)
- if(H.s_store)
- H.s_store.screen_loc = ui_sstore1
- screenmob.client.screen += H.s_store
- if(H.wear_id)
- H.wear_id.screen_loc = ui_id
- screenmob.client.screen += H.wear_id
- if(H.belt)
- H.belt.screen_loc = ui_belt
- screenmob.client.screen += H.belt
- if(H.back)
- H.back.screen_loc = ui_back
- screenmob.client.screen += H.back
- if(H.l_store)
- H.l_store.screen_loc = ui_storage1
- screenmob.client.screen += H.l_store
- if(H.r_store)
- H.r_store.screen_loc = ui_storage2
- screenmob.client.screen += H.r_store
- else
- if(H.s_store)
- screenmob.client.screen -= H.s_store
- if(H.wear_id)
- screenmob.client.screen -= H.wear_id
- if(H.belt)
- screenmob.client.screen -= H.belt
- if(H.back)
- screenmob.client.screen -= H.back
- if(H.l_store)
- screenmob.client.screen -= H.l_store
- if(H.r_store)
- screenmob.client.screen -= H.r_store
-
- if(hud_version != HUD_STYLE_NOHUD)
- for(var/obj/item/I in H.held_items)
- I.screen_loc = ui_hand_position(H.get_held_index_of_item(I))
- screenmob.client.screen += I
- else
- for(var/obj/item/I in H.held_items)
- I.screen_loc = null
- screenmob.client.screen -= I
-
-
-/mob/living/carbon/human/verb/toggle_hotkey_verbs()
- set category = "OOC"
- set name = "Toggle hotkey buttons"
- set desc = "This disables or enables the user interface buttons which can be used with hotkeys."
-
- if(hud_used.hotkey_ui_hidden)
- client.screen += hud_used.hotkeybuttons
- hud_used.hotkey_ui_hidden = 0
- else
- client.screen -= hud_used.hotkeybuttons
- hud_used.hotkey_ui_hidden = 1
+/obj/screen/human
+ icon = 'icons/mob/screen_midnight.dmi'
+
+/obj/screen/human/toggle
+ name = "toggle"
+ icon_state = "toggle"
+
+/obj/screen/human/toggle/Click()
+
+ var/mob/targetmob = usr
+
+ if(isobserver(usr))
+ if(ishuman(usr.client.eye) && (usr.client.eye != usr))
+ var/mob/M = usr.client.eye
+ targetmob = M
+
+ if(usr.hud_used.inventory_shown && targetmob.hud_used)
+ usr.hud_used.inventory_shown = 0
+ usr.client.screen -= targetmob.hud_used.toggleable_inventory
+ else
+ usr.hud_used.inventory_shown = 1
+ usr.client.screen += targetmob.hud_used.toggleable_inventory
+
+ targetmob.hud_used.hidden_inventory_update(usr)
+
+/obj/screen/human/equip
+ name = "equip"
+ icon_state = "act_equip"
+
+/obj/screen/human/equip/Click()
+ if(istype(usr.loc,/obj/mecha)) // stops inventory actions in a mech
+ return 1
+ var/mob/living/carbon/human/H = usr
+ H.quick_equip()
+
+/obj/screen/devil
+ invisibility = INVISIBILITY_ABSTRACT
+
+/obj/screen/devil/soul_counter
+ icon = 'icons/mob/screen_gen.dmi'
+ name = "souls owned"
+ icon_state = "Devil-6"
+ screen_loc = ui_devilsouldisplay
+
+/obj/screen/devil/soul_counter/proc/update_counter(souls = 0)
+ invisibility = 0
+ maptext = "[souls]
"
+ switch(souls)
+ if(0,null)
+ icon_state = "Devil-1"
+ if(1,2)
+ icon_state = "Devil-2"
+ if(3 to 5)
+ icon_state = "Devil-3"
+ if(6 to 8)
+ icon_state = "Devil-4"
+ if(9 to INFINITY)
+ icon_state = "Devil-5"
+ else
+ icon_state = "Devil-6"
+
+/obj/screen/devil/soul_counter/proc/clear()
+ invisibility = INVISIBILITY_ABSTRACT
+
+/obj/screen/ling
+ invisibility = INVISIBILITY_ABSTRACT
+
+/obj/screen/ling/sting
+ name = "current sting"
+ screen_loc = ui_lingstingdisplay
+
+/obj/screen/ling/sting/Click()
+ if(isobserver(usr))
+ return
+ var/mob/living/carbon/U = usr
+ U.unset_sting()
+
+/obj/screen/ling/chems
+ name = "chemical storage"
+ icon_state = "power_display"
+ screen_loc = ui_lingchemdisplay
+
+/mob/living/carbon/human/create_mob_hud()
+ if(client && !hud_used)
+ hud_used = new /datum/hud/human(src, ui_style2icon(client.prefs.UI_style))
+
+
+/datum/hud/human/New(mob/living/carbon/human/owner, ui_style = 'icons/mob/screen_midnight.dmi')
+ ..()
+ owner.overlay_fullscreen("see_through_darkness", /obj/screen/fullscreen/see_through_darkness)
+
+ var/obj/screen/using
+ var/obj/screen/inventory/inv_box
+
+ using = new /obj/screen/craft
+ using.icon = ui_style
+ static_inventory += using
+
+ using = new/obj/screen/language_menu
+ using.icon = ui_style
+ static_inventory += using
+
+ using = new /obj/screen/area_creator
+ using.icon = ui_style
+ static_inventory += using
+
+ action_intent = new /obj/screen/act_intent/segmented
+ action_intent.icon_state = mymob.a_intent
+ static_inventory += action_intent
+
+ using = new /obj/screen/mov_intent
+ using.icon = ui_style
+ using.icon_state = (mymob.m_intent == MOVE_INTENT_RUN ? "running" : "walking")
+ using.screen_loc = ui_movi
+ static_inventory += using
+
+ using = new /obj/screen/drop()
+ using.icon = ui_style
+ using.screen_loc = ui_drop_throw
+ static_inventory += using
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "i_clothing"
+ inv_box.icon = ui_style
+ inv_box.slot_id = slot_w_uniform
+ inv_box.icon_state = "uniform"
+ inv_box.screen_loc = ui_iclothing
+ toggleable_inventory += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "o_clothing"
+ inv_box.icon = ui_style
+ inv_box.slot_id = slot_wear_suit
+ inv_box.icon_state = "suit"
+ inv_box.screen_loc = ui_oclothing
+ toggleable_inventory += inv_box
+
+ build_hand_slots(ui_style)
+
+ using = new /obj/screen/swap_hand()
+ using.icon = ui_style
+ using.icon_state = "swap_1"
+ using.screen_loc = ui_swaphand_position(owner,1)
+ static_inventory += using
+
+ using = new /obj/screen/swap_hand()
+ using.icon = ui_style
+ using.icon_state = "swap_2"
+ using.screen_loc = ui_swaphand_position(owner,2)
+ static_inventory += using
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "id"
+ inv_box.icon = ui_style
+ inv_box.icon_state = "id"
+ inv_box.screen_loc = ui_id
+ inv_box.slot_id = slot_wear_id
+ static_inventory += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "mask"
+ inv_box.icon = ui_style
+ inv_box.icon_state = "mask"
+ inv_box.screen_loc = ui_mask
+ inv_box.slot_id = slot_wear_mask
+ toggleable_inventory += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "neck"
+ inv_box.icon = ui_style
+ inv_box.icon_state = "neck"
+ inv_box.screen_loc = ui_neck
+ inv_box.slot_id = slot_neck
+ toggleable_inventory += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "back"
+ inv_box.icon = ui_style
+ inv_box.icon_state = "back"
+ inv_box.screen_loc = ui_back
+ inv_box.slot_id = slot_back
+ static_inventory += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "storage1"
+ inv_box.icon = ui_style
+ inv_box.icon_state = "pocket"
+ inv_box.screen_loc = ui_storage1
+ inv_box.slot_id = slot_l_store
+ static_inventory += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "storage2"
+ inv_box.icon = ui_style
+ inv_box.icon_state = "pocket"
+ inv_box.screen_loc = ui_storage2
+ inv_box.slot_id = slot_r_store
+ static_inventory += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "suit storage"
+ inv_box.icon = ui_style
+ inv_box.icon_state = "suit_storage"
+ inv_box.screen_loc = ui_sstore1
+ inv_box.slot_id = slot_s_store
+ static_inventory += inv_box
+
+ using = new /obj/screen/resist()
+ using.icon = ui_style
+ using.screen_loc = ui_pull_resist
+ hotkeybuttons += using
+
+ using = new /obj/screen/human/toggle()
+ using.icon = ui_style
+ using.screen_loc = ui_inventory
+ static_inventory += using
+
+ using = new /obj/screen/human/equip()
+ using.icon = ui_style
+ using.screen_loc = ui_equip_position(mymob)
+ static_inventory += using
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "gloves"
+ inv_box.icon = ui_style
+ inv_box.icon_state = "gloves"
+ inv_box.screen_loc = ui_gloves
+ inv_box.slot_id = slot_gloves
+ toggleable_inventory += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "eyes"
+ inv_box.icon = ui_style
+ inv_box.icon_state = "glasses"
+ inv_box.screen_loc = ui_glasses
+ inv_box.slot_id = slot_glasses
+ toggleable_inventory += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "ears"
+ inv_box.icon = ui_style
+ inv_box.icon_state = "ears"
+ inv_box.screen_loc = ui_ears
+ inv_box.slot_id = slot_ears
+ toggleable_inventory += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "head"
+ inv_box.icon = ui_style
+ inv_box.icon_state = "head"
+ inv_box.screen_loc = ui_head
+ inv_box.slot_id = slot_head
+ toggleable_inventory += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "shoes"
+ inv_box.icon = ui_style
+ inv_box.icon_state = "shoes"
+ inv_box.screen_loc = ui_shoes
+ inv_box.slot_id = slot_shoes
+ toggleable_inventory += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "belt"
+ inv_box.icon = ui_style
+ inv_box.icon_state = "belt"
+// inv_box.icon_full = "template_small"
+ inv_box.screen_loc = ui_belt
+ inv_box.slot_id = slot_belt
+ static_inventory += inv_box
+
+ throw_icon = new /obj/screen/throw_catch()
+ throw_icon.icon = ui_style
+ throw_icon.screen_loc = ui_drop_throw
+ hotkeybuttons += throw_icon
+
+ internals = new /obj/screen/internals()
+ infodisplay += internals
+
+ healths = new /obj/screen/healths()
+ infodisplay += healths
+
+ //citadel code
+ arousal = new /obj/screen/arousal()
+ infodisplay += arousal
+
+ healthdoll = new /obj/screen/healthdoll()
+ infodisplay += healthdoll
+
+ pull_icon = new /obj/screen/pull()
+ pull_icon.icon = ui_style
+ pull_icon.update_icon(mymob)
+ pull_icon.screen_loc = ui_pull_resist
+ static_inventory += pull_icon
+
+ lingchemdisplay = new /obj/screen/ling/chems()
+ infodisplay += lingchemdisplay
+
+ lingstingdisplay = new /obj/screen/ling/sting()
+ infodisplay += lingstingdisplay
+
+ devilsouldisplay = new /obj/screen/devil/soul_counter
+ infodisplay += devilsouldisplay
+
+ zone_select = new /obj/screen/zone_sel()
+ zone_select.icon = ui_style
+ zone_select.update_icon(mymob)
+ static_inventory += zone_select
+
+ for(var/obj/screen/inventory/inv in (static_inventory + toggleable_inventory))
+ if(inv.slot_id)
+ inv.hud = src
+ inv_slots[inv.slot_id] = inv
+ inv.update_icon()
+
+/datum/hud/human/update_locked_slots()
+ if(!mymob)
+ return
+ var/mob/living/carbon/human/H = mymob
+ var/datum/species/S = H.dna.species
+ for(var/obj/screen/inventory/inv in (static_inventory + toggleable_inventory))
+ if(inv.slot_id)
+ if(inv.slot_id in S.no_equip)
+ inv.alpha = 128
+ else
+ inv.alpha = initial(inv.alpha)
+
+/datum/hud/human/hidden_inventory_update(mob/viewer)
+ if(!mymob)
+ return
+ var/mob/living/carbon/human/H = mymob
+
+ var/mob/screenmob = viewer || H
+
+ if(screenmob.hud_used.inventory_shown && screenmob.hud_used.hud_shown)
+ if(H.shoes)
+ H.shoes.screen_loc = ui_shoes
+ screenmob.client.screen += H.shoes
+ if(H.gloves)
+ H.gloves.screen_loc = ui_gloves
+ screenmob.client.screen += H.gloves
+ if(H.ears)
+ H.ears.screen_loc = ui_ears
+ screenmob.client.screen += H.ears
+ if(H.glasses)
+ H.glasses.screen_loc = ui_glasses
+ screenmob.client.screen += H.glasses
+ if(H.w_uniform)
+ H.w_uniform.screen_loc = ui_iclothing
+ screenmob.client.screen += H.w_uniform
+ if(H.wear_suit)
+ H.wear_suit.screen_loc = ui_oclothing
+ screenmob.client.screen += H.wear_suit
+ if(H.wear_mask)
+ H.wear_mask.screen_loc = ui_mask
+ screenmob.client.screen += H.wear_mask
+ if(H.wear_neck)
+ H.wear_neck.screen_loc = ui_neck
+ screenmob.client.screen += H.wear_neck
+ if(H.head)
+ H.head.screen_loc = ui_head
+ screenmob.client.screen += H.head
+ else
+ if(H.shoes) screenmob.client.screen -= H.shoes
+ if(H.gloves) screenmob.client.screen -= H.gloves
+ if(H.ears) screenmob.client.screen -= H.ears
+ if(H.glasses) screenmob.client.screen -= H.glasses
+ if(H.w_uniform) screenmob.client.screen -= H.w_uniform
+ if(H.wear_suit) screenmob.client.screen -= H.wear_suit
+ if(H.wear_mask) screenmob.client.screen -= H.wear_mask
+ if(H.wear_neck) screenmob.client.screen -= H.wear_neck
+ if(H.head) screenmob.client.screen -= H.head
+
+
+
+/datum/hud/human/persistent_inventory_update(mob/viewer)
+ if(!mymob)
+ return
+ ..()
+ var/mob/living/carbon/human/H = mymob
+
+ var/mob/screenmob = viewer || H
+
+ if(screenmob.hud_used)
+ if(screenmob.hud_used.hud_shown)
+ if(H.s_store)
+ H.s_store.screen_loc = ui_sstore1
+ screenmob.client.screen += H.s_store
+ if(H.wear_id)
+ H.wear_id.screen_loc = ui_id
+ screenmob.client.screen += H.wear_id
+ if(H.belt)
+ H.belt.screen_loc = ui_belt
+ screenmob.client.screen += H.belt
+ if(H.back)
+ H.back.screen_loc = ui_back
+ screenmob.client.screen += H.back
+ if(H.l_store)
+ H.l_store.screen_loc = ui_storage1
+ screenmob.client.screen += H.l_store
+ if(H.r_store)
+ H.r_store.screen_loc = ui_storage2
+ screenmob.client.screen += H.r_store
+ else
+ if(H.s_store)
+ screenmob.client.screen -= H.s_store
+ if(H.wear_id)
+ screenmob.client.screen -= H.wear_id
+ if(H.belt)
+ screenmob.client.screen -= H.belt
+ if(H.back)
+ screenmob.client.screen -= H.back
+ if(H.l_store)
+ screenmob.client.screen -= H.l_store
+ if(H.r_store)
+ screenmob.client.screen -= H.r_store
+
+ if(hud_version != HUD_STYLE_NOHUD)
+ for(var/obj/item/I in H.held_items)
+ I.screen_loc = ui_hand_position(H.get_held_index_of_item(I))
+ screenmob.client.screen += I
+ else
+ for(var/obj/item/I in H.held_items)
+ I.screen_loc = null
+ screenmob.client.screen -= I
+
+
+/mob/living/carbon/human/verb/toggle_hotkey_verbs()
+ set category = "OOC"
+ set name = "Toggle hotkey buttons"
+ set desc = "This disables or enables the user interface buttons which can be used with hotkeys."
+
+ if(hud_used.hotkey_ui_hidden)
+ client.screen += hud_used.hotkeybuttons
+ hud_used.hotkey_ui_hidden = 0
+ else
+ client.screen -= hud_used.hotkeybuttons
+ hud_used.hotkey_ui_hidden = 1
diff --git a/code/datums/browser.dm b/code/datums/browser.dm
index 9b0f4a91e6..282759b961 100644
--- a/code/datums/browser.dm
+++ b/code/datums/browser.dm
@@ -169,7 +169,7 @@
opentime = 0
/datum/browser/alert/proc/wait()
- while (opentime && selectedbutton <= 0 && (!timeout || opentime+timeout > world.time))
+ while (opentime && selectedbutton <= 0 && (!timeout || opentime+timeout > world.time))
stoplag()
/datum/browser/alert/Topic(href,href_list)
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 02d0d38cca..77628eb9be 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -615,7 +615,9 @@
if(!H.has_language(dt))
return FALSE
- else if(H.omnitongue || could_speak_in_language(dt))
+ else if(H.omnitongue)
+ return TRUE
+ else if(could_speak_in_language(dt) && (!H.only_speaks_language || H.only_speaks_language == dt))
return TRUE
else
return FALSE
@@ -631,8 +633,6 @@
else
H.selected_default_language = null
-
-
var/datum/language/chosen_langtype
var/highest_priority
diff --git a/code/game/gamemodes/nuclear/pinpointer.dm b/code/game/gamemodes/nuclear/pinpointer.dm
index 1587f233d9..45f7c5262a 100644
--- a/code/game/gamemodes/nuclear/pinpointer.dm
+++ b/code/game/gamemodes/nuclear/pinpointer.dm
@@ -1,177 +1,177 @@
-//Pinpointers are used to track atoms from a distance as long as they're on the same z-level. The captain and nuke ops have ones that track the nuclear authentication disk.
-/obj/item/weapon/pinpointer
- name = "pinpointer"
- desc = "A handheld tracking device that locks onto certain signals."
- icon = 'icons/obj/device.dmi'
- icon_state = "pinoff"
- flags = CONDUCT
- slot_flags = SLOT_BELT
- w_class = WEIGHT_CLASS_SMALL
- item_state = "electronic"
- throw_speed = 3
- throw_range = 7
- materials = list(MAT_METAL = 500, MAT_GLASS = 250)
- resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
- var/active = FALSE
- var/atom/movable/target = null //The thing we're searching for
- var/atom/movable/constant_target = null //The thing we're always focused on, if we're in the right mode
- var/target_x = 0 //The target coordinates if we're tracking those
- var/target_y = 0
- var/minimum_range = 0 //at what range the pinpointer declares you to be at your destination
- var/nuke_warning = FALSE // If we've set off a miniature alarm about an armed nuke
- var/mode = TRACK_NUKE_DISK //What are we looking for?
-
-/obj/item/weapon/pinpointer/New()
- ..()
- GLOB.pinpointer_list += src
-
-/obj/item/weapon/pinpointer/Destroy()
- STOP_PROCESSING(SSfastprocess, src)
- GLOB.pinpointer_list -= src
- return ..()
-
-/obj/item/weapon/pinpointer/attack_self(mob/living/user)
- active = !active
- user.visible_message("[user] [active ? "" : "de"]activates their pinpointer.", "You [active ? "" : "de"]activate your pinpointer.")
- playsound(user, 'sound/items/Screwdriver2.ogg', 50, 1)
- icon_state = "pin[active ? "onnull" : "off"]"
- if(active)
- START_PROCESSING(SSfastprocess, src)
- else
- target = null //Restarting the pinpointer forces a target reset
- STOP_PROCESSING(SSfastprocess, src)
-
-/obj/item/weapon/pinpointer/attackby(obj/item/I, mob/living/user, params)
- if(mode != TRACK_ATOM)
- return ..()
- user.visible_message("[user] tunes [src] to [I].", "You fine-tune [src]'s tracking to track [I].")
- playsound(src, 'sound/machines/click.ogg', 50, 1)
- constant_target = I
-
-/obj/item/weapon/pinpointer/examine(mob/user)
- ..()
- var/msg = "Its tracking indicator reads "
- switch(mode)
- if(TRACK_NUKE_DISK)
- msg += "\"nuclear_disk\"."
- if(TRACK_MALF_AI)
- msg += "\"01000001 01001001\"."
- if(TRACK_INFILTRATOR)
- msg += "\"vasvygengbefuvc\"."
- if(TRACK_OPERATIVES)
- msg += "\"[target ? "Operative [target]" : "friends"]\"."
- if(TRACK_ATOM)
- msg += "\"[initial(constant_target.name)]\"."
- if(TRACK_COORDINATES)
- msg += "\"([target_x], [target_y])\"."
- else
- msg = "Its tracking indicator is blank."
- to_chat(user, msg)
- for(var/obj/machinery/nuclearbomb/bomb in GLOB.machines)
- if(bomb.timing)
- to_chat(user, "Extreme danger. Arming signal detected. Time remaining: [bomb.get_time_left()]")
-
-/obj/item/weapon/pinpointer/process()
- if(!active)
- STOP_PROCESSING(SSfastprocess, src)
- return
- scan_for_target()
- point_to_target()
- my_god_jc_a_bomb()
- addtimer(CALLBACK(src, .proc/refresh_target), 50, TIMER_UNIQUE)
-
-/obj/item/weapon/pinpointer/proc/scan_for_target() //Looks for whatever it's tracking
- if(target)
- if(isliving(target))
- var/mob/living/L = target
- if(L.stat == DEAD)
- target = null
- return
- switch(mode)
- if(TRACK_NUKE_DISK)
- var/obj/item/weapon/disk/nuclear/N = locate()
- target = N
- if(TRACK_MALF_AI)
- for(var/V in GLOB.ai_list)
- var/mob/living/silicon/ai/A = V
- if(A.nuking)
- target = A
- for(var/V in GLOB.apcs_list)
- var/obj/machinery/power/apc/A = V
- if(A.malfhack && A.occupier)
- target = A
- if(TRACK_INFILTRATOR)
- target = SSshuttle.getShuttle("syndicate")
- if(TRACK_OPERATIVES)
- var/list/possible_targets = list()
- var/turf/here = get_turf(src)
- for(var/V in SSticker.mode.syndicates)
- var/datum/mind/M = V
- if(M.current && M.current.stat != DEAD)
- possible_targets |= M.current
- var/mob/living/closest_operative = get_closest_atom(/mob/living/carbon/human, possible_targets, here)
- if(closest_operative)
- target = closest_operative
- if(TRACK_ATOM)
- if(constant_target)
- target = constant_target
- if(TRACK_COORDINATES)
- var/turf/T = get_turf(src)
- target = locate(target_x, target_y, T.z)
-
-/obj/item/weapon/pinpointer/proc/point_to_target() //If we found what we're looking for, show the distance and direction
- if(!active)
- return
- if(!target || (mode == TRACK_ATOM && !constant_target))
- icon_state = "pinon[nuke_warning ? "alert" : ""]null"
- return
- var/turf/here = get_turf(src)
- var/turf/there = get_turf(target)
- if(here.z != there.z)
- icon_state = "pinon[nuke_warning ? "alert" : ""]null"
- return
- if(get_dist_euclidian(here,there)<=minimum_range)
- icon_state = "pinon[nuke_warning ? "alert" : ""]direct"
- else
- setDir(get_dir(here, there))
- switch(get_dist(here, there))
- if(1 to 8)
- icon_state = "pinon[nuke_warning ? "alert" : "close"]"
- if(9 to 16)
- icon_state = "pinon[nuke_warning ? "alert" : "medium"]"
- if(16 to INFINITY)
- icon_state = "pinon[nuke_warning ? "alert" : "far"]"
-
-/obj/item/weapon/pinpointer/proc/my_god_jc_a_bomb() //If we should get the hell back to the ship
- for(var/obj/machinery/nuclearbomb/bomb in GLOB.nuke_list)
- if(bomb.timing)
- if(!nuke_warning)
- nuke_warning = TRUE
- playsound(src, 'sound/items/Nuke_toy_lowpower.ogg', 50, 0)
- if(isliving(loc))
- var/mob/living/L = loc
- to_chat(L, "Your [name] vibrates and lets out a tinny alarm. Uh oh.")
-
-/obj/item/weapon/pinpointer/proc/switch_mode_to(new_mode) //If we shouldn't be tracking what we are
- if(isliving(loc))
- var/mob/living/L = loc
- to_chat(L, "Your [name] beeps as it reconfigures its tracking algorithms.")
- playsound(L, 'sound/machines/triple_beep.ogg', 50, 1)
- mode = new_mode
- target = null //Switch modes so we can find the new target
-
-/obj/item/weapon/pinpointer/proc/refresh_target() //Periodically removes the target to allow the pinpointer to update (i.e. malf AI shunts, an operative dies)
- target = null
-
-/obj/item/weapon/pinpointer/syndicate //Syndicate pinpointers automatically point towards the infiltrator once the nuke is active.
- name = "syndicate pinpointer"
- desc = "A handheld tracking device that locks onto certain signals. It's configured to switch tracking modes once it detects the activation signal of a nuclear device."
-
-/obj/item/weapon/pinpointer/syndicate/cyborg //Cyborg pinpointers just look for a random operative.
- name = "cyborg syndicate pinpointer"
- desc = "An integrated tracking device, jury-rigged to search for living Syndicate operatives."
- mode = TRACK_OPERATIVES
- flags = NODROP
-
-
-
+//Pinpointers are used to track atoms from a distance as long as they're on the same z-level. The captain and nuke ops have ones that track the nuclear authentication disk.
+/obj/item/weapon/pinpointer
+ name = "pinpointer"
+ desc = "A handheld tracking device that locks onto certain signals."
+ icon = 'icons/obj/device.dmi'
+ icon_state = "pinoff"
+ flags = CONDUCT
+ slot_flags = SLOT_BELT
+ w_class = WEIGHT_CLASS_SMALL
+ item_state = "electronic"
+ throw_speed = 3
+ throw_range = 7
+ materials = list(MAT_METAL = 500, MAT_GLASS = 250)
+ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
+ var/active = FALSE
+ var/atom/movable/target = null //The thing we're searching for
+ var/atom/movable/constant_target = null //The thing we're always focused on, if we're in the right mode
+ var/target_x = 0 //The target coordinates if we're tracking those
+ var/target_y = 0
+ var/minimum_range = 0 //at what range the pinpointer declares you to be at your destination
+ var/nuke_warning = FALSE // If we've set off a miniature alarm about an armed nuke
+ var/mode = TRACK_NUKE_DISK //What are we looking for?
+
+/obj/item/weapon/pinpointer/New()
+ ..()
+ GLOB.pinpointer_list += src
+
+/obj/item/weapon/pinpointer/Destroy()
+ STOP_PROCESSING(SSfastprocess, src)
+ GLOB.pinpointer_list -= src
+ return ..()
+
+/obj/item/weapon/pinpointer/attack_self(mob/living/user)
+ active = !active
+ user.visible_message("[user] [active ? "" : "de"]activates their pinpointer.", "You [active ? "" : "de"]activate your pinpointer.")
+ playsound(user, 'sound/items/Screwdriver2.ogg', 50, 1)
+ icon_state = "pin[active ? "onnull" : "off"]"
+ if(active)
+ START_PROCESSING(SSfastprocess, src)
+ else
+ target = null //Restarting the pinpointer forces a target reset
+ STOP_PROCESSING(SSfastprocess, src)
+
+/obj/item/weapon/pinpointer/attackby(obj/item/I, mob/living/user, params)
+ if(mode != TRACK_ATOM)
+ return ..()
+ user.visible_message("[user] tunes [src] to [I].", "You fine-tune [src]'s tracking to track [I].")
+ playsound(src, 'sound/machines/click.ogg', 50, 1)
+ constant_target = I
+
+/obj/item/weapon/pinpointer/examine(mob/user)
+ ..()
+ var/msg = "Its tracking indicator reads "
+ switch(mode)
+ if(TRACK_NUKE_DISK)
+ msg += "\"nuclear_disk\"."
+ if(TRACK_MALF_AI)
+ msg += "\"01000001 01001001\"."
+ if(TRACK_INFILTRATOR)
+ msg += "\"vasvygengbefuvc\"."
+ if(TRACK_OPERATIVES)
+ msg += "\"[target ? "Operative [target]" : "friends"]\"."
+ if(TRACK_ATOM)
+ msg += "\"[initial(constant_target.name)]\"."
+ if(TRACK_COORDINATES)
+ msg += "\"([target_x], [target_y])\"."
+ else
+ msg = "Its tracking indicator is blank."
+ to_chat(user, msg)
+ for(var/obj/machinery/nuclearbomb/bomb in GLOB.machines)
+ if(bomb.timing)
+ to_chat(user, "Extreme danger. Arming signal detected. Time remaining: [bomb.get_time_left()]")
+
+/obj/item/weapon/pinpointer/process()
+ if(!active)
+ STOP_PROCESSING(SSfastprocess, src)
+ return
+ scan_for_target()
+ point_to_target()
+ my_god_jc_a_bomb()
+ addtimer(CALLBACK(src, .proc/refresh_target), 50, TIMER_UNIQUE)
+
+/obj/item/weapon/pinpointer/proc/scan_for_target() //Looks for whatever it's tracking
+ if(target)
+ if(isliving(target))
+ var/mob/living/L = target
+ if(L.stat == DEAD)
+ target = null
+ return
+ switch(mode)
+ if(TRACK_NUKE_DISK)
+ var/obj/item/weapon/disk/nuclear/N = locate()
+ target = N
+ if(TRACK_MALF_AI)
+ for(var/V in GLOB.ai_list)
+ var/mob/living/silicon/ai/A = V
+ if(A.nuking)
+ target = A
+ for(var/V in GLOB.apcs_list)
+ var/obj/machinery/power/apc/A = V
+ if(A.malfhack && A.occupier)
+ target = A
+ if(TRACK_INFILTRATOR)
+ target = SSshuttle.getShuttle("syndicate")
+ if(TRACK_OPERATIVES)
+ var/list/possible_targets = list()
+ var/turf/here = get_turf(src)
+ for(var/V in SSticker.mode.syndicates)
+ var/datum/mind/M = V
+ if(M.current && M.current.stat != DEAD)
+ possible_targets |= M.current
+ var/mob/living/closest_operative = get_closest_atom(/mob/living/carbon/human, possible_targets, here)
+ if(closest_operative)
+ target = closest_operative
+ if(TRACK_ATOM)
+ if(constant_target)
+ target = constant_target
+ if(TRACK_COORDINATES)
+ var/turf/T = get_turf(src)
+ target = locate(target_x, target_y, T.z)
+
+/obj/item/weapon/pinpointer/proc/point_to_target() //If we found what we're looking for, show the distance and direction
+ if(!active)
+ return
+ if(!target || (mode == TRACK_ATOM && !constant_target))
+ icon_state = "pinon[nuke_warning ? "alert" : ""]null"
+ return
+ var/turf/here = get_turf(src)
+ var/turf/there = get_turf(target)
+ if(here.z != there.z)
+ icon_state = "pinon[nuke_warning ? "alert" : ""]null"
+ return
+ if(get_dist_euclidian(here,there)<=minimum_range)
+ icon_state = "pinon[nuke_warning ? "alert" : ""]direct"
+ else
+ setDir(get_dir(here, there))
+ switch(get_dist(here, there))
+ if(1 to 8)
+ icon_state = "pinon[nuke_warning ? "alert" : "close"]"
+ if(9 to 16)
+ icon_state = "pinon[nuke_warning ? "alert" : "medium"]"
+ if(16 to INFINITY)
+ icon_state = "pinon[nuke_warning ? "alert" : "far"]"
+
+/obj/item/weapon/pinpointer/proc/my_god_jc_a_bomb() //If we should get the hell back to the ship
+ for(var/obj/machinery/nuclearbomb/bomb in GLOB.nuke_list)
+ if(bomb.timing)
+ if(!nuke_warning)
+ nuke_warning = TRUE
+ playsound(src, 'sound/items/Nuke_toy_lowpower.ogg', 50, 0)
+ if(isliving(loc))
+ var/mob/living/L = loc
+ to_chat(L, "Your [name] vibrates and lets out a tinny alarm. Uh oh.")
+
+/obj/item/weapon/pinpointer/proc/switch_mode_to(new_mode) //If we shouldn't be tracking what we are
+ if(isliving(loc))
+ var/mob/living/L = loc
+ to_chat(L, "Your [name] beeps as it reconfigures its tracking algorithms.")
+ playsound(L, 'sound/machines/triple_beep.ogg', 50, 1)
+ mode = new_mode
+ target = null //Switch modes so we can find the new target
+
+/obj/item/weapon/pinpointer/proc/refresh_target() //Periodically removes the target to allow the pinpointer to update (i.e. malf AI shunts, an operative dies)
+ target = null
+
+/obj/item/weapon/pinpointer/syndicate //Syndicate pinpointers automatically point towards the infiltrator once the nuke is active.
+ name = "syndicate pinpointer"
+ desc = "A handheld tracking device that locks onto certain signals. It's configured to switch tracking modes once it detects the activation signal of a nuclear device."
+
+/obj/item/weapon/pinpointer/syndicate/cyborg //Cyborg pinpointers just look for a random operative.
+ name = "cyborg syndicate pinpointer"
+ desc = "An integrated tracking device, jury-rigged to search for living Syndicate operatives."
+ mode = TRACK_OPERATIVES
+ flags = NODROP
+
+
+
diff --git a/code/game/machinery/computer/telecrystalconsoles.dm b/code/game/machinery/computer/telecrystalconsoles.dm
index cfbf112bba..98450453bd 100644
--- a/code/game/machinery/computer/telecrystalconsoles.dm
+++ b/code/game/machinery/computer/telecrystalconsoles.dm
@@ -1,223 +1,223 @@
-#define NUKESCALINGMODIFIER 1
-
-GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","Echo","Foxtrot","Zero", "Niner"))
-
-/obj/machinery/computer/telecrystals
- name = "\improper Telecrystal assignment station"
- desc = "A device used to manage telecrystals during group operations. You shouldn't be looking at this particular one..."
- icon_state = "tcstation"
- icon_keyboard = "tcstation_key"
- icon_screen = "syndie"
- clockwork = TRUE //it'd look weird, at least if ratvar ever got there
- resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
-
- light_color = LIGHT_COLOR_RED
-
-/////////////////////////////////////////////
-/obj/machinery/computer/telecrystals/uplinker
- name = "\improper Telecrystal upload/receive station"
- desc = "A device used to manage telecrystals during group operations. To use, simply insert your uplink. With your uplink installed \
- you can upload your telecrystals to the group's pool using the console, or be assigned additional telecrystals by your lieutenant."
- var/obj/item/uplinkholder = null
- var/obj/machinery/computer/telecrystals/boss/linkedboss = null
-
-/obj/machinery/computer/telecrystals/uplinker/Initialize()
- ..()
-
- var/ID = pick_n_take(GLOB.possible_uplinker_IDs)
- if(!ID)
- ID = rand(1,999)
- name = "[name] [ID]"
-
-/obj/machinery/computer/telecrystals/uplinker/attackby(obj/item/O, mob/user, params)
- if(uplinkholder)
- to_chat(user, "The [src] already has an uplink in it.")
- return
- if(O.hidden_uplink)
- var/obj/item/I = user.get_active_held_item()
- if(!user.drop_item())
- return
- uplinkholder = I
- I.loc = src
- I.add_fingerprint(user)
- update_icon()
- updateUsrDialog()
- else
- to_chat(user, "The [O] doesn't appear to be an uplink...")
-
-/obj/machinery/computer/telecrystals/uplinker/update_icon()
- ..()
- if(uplinkholder)
- add_overlay("[initial(icon_state)]-closed")
-
-/obj/machinery/computer/telecrystals/uplinker/proc/ejectuplink()
- if(uplinkholder)
- uplinkholder.loc = get_turf(src.loc)
- uplinkholder = null
- update_icon()
-
-/obj/machinery/computer/telecrystals/uplinker/proc/donateTC(amt, addLog = 1)
- if(uplinkholder && linkedboss)
- if(amt < 0)
- linkedboss.storedcrystals += uplinkholder.hidden_uplink.telecrystals
- if(addLog)
- linkedboss.logTransfer("[src] donated [uplinkholder.hidden_uplink.telecrystals] telecrystals to [linkedboss].")
- uplinkholder.hidden_uplink.telecrystals = 0
- else if(amt <= uplinkholder.hidden_uplink.telecrystals)
- uplinkholder.hidden_uplink.telecrystals -= amt
- linkedboss.storedcrystals += amt
- if(addLog)
- linkedboss.logTransfer("[src] donated [amt] telecrystals to [linkedboss].")
-
-/obj/machinery/computer/telecrystals/uplinker/proc/giveTC(amt, addLog = 1)
- if(uplinkholder && linkedboss)
- if(amt < 0)
- uplinkholder.hidden_uplink.telecrystals += linkedboss.storedcrystals
- if(addLog)
- linkedboss.logTransfer("[src] received [linkedboss.storedcrystals] telecrystals from [linkedboss].")
- linkedboss.storedcrystals = 0
- else if(amt <= linkedboss.storedcrystals)
- uplinkholder.hidden_uplink.telecrystals += amt
- linkedboss.storedcrystals -= amt
- if(addLog)
- linkedboss.logTransfer("[src] received [amt] telecrystals from [linkedboss].")
-
-///////
-
-/obj/machinery/computer/telecrystals/uplinker/attack_hand(mob/user)
- if(..())
- return
- src.add_fingerprint(user)
- user.set_machine(src)
-
- var/dat = ""
- if(linkedboss)
- dat += "[linkedboss] has [linkedboss.storedcrystals] telecrystals available for distribution.
"
- else
- dat += "No linked management consoles detected. Scan for uplink stations using the management console.
"
-
- if(uplinkholder)
- dat += "[uplinkholder.hidden_uplink.telecrystals] telecrystals remain in this uplink.
"
- if(linkedboss)
- dat += "Donate TC: 1 | 5 | All"
- dat += "
Eject Uplink"
-
-
- var/datum/browser/popup = new(user, "computer", "Telecrystal Upload/Receive Station", 700, 500)
- popup.set_content(dat)
- popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
- popup.open()
- return
-
-/obj/machinery/computer/telecrystals/uplinker/Topic(href, href_list)
- if(..())
- return
-
- if(href_list["donate"])
- var/tcamt = text2num(href_list["donate"])
- donateTC(tcamt)
-
- if(href_list["eject"])
- ejectuplink()
-
- src.updateUsrDialog()
-
-
-/////////////////////////////////////////
-/obj/machinery/computer/telecrystals/boss
- name = "team Telecrystal management console"
- desc = "A device used to manage telecrystals during group operations. To use, simply initialize the machine by scanning for nearby uplink stations. \
- Once the consoles are linked up, you can assign any telecrystals amongst your operatives; be they donated by your agents or rationed to the squad \
- based on the danger rating of the mission."
- icon_state = "computer"
- icon_screen = "tcboss"
- icon_keyboard = "syndie_key"
- var/virgin = 1
- var/scanrange = 10
- var/storedcrystals = 0
- var/list/TCstations = list()
- var/list/transferlog = list()
-
-/obj/machinery/computer/telecrystals/boss/proc/logTransfer(logmessage)
- transferlog += ("[worldtime2text()] [logmessage]")
-
-/obj/machinery/computer/telecrystals/boss/proc/scanUplinkers()
- for(var/obj/machinery/computer/telecrystals/uplinker/A in urange(scanrange, src.loc))
- if(!A.linkedboss)
- TCstations += A
- A.linkedboss = src
- if(virgin)
- getDangerous()
- virgin = 0
-
-/obj/machinery/computer/telecrystals/boss/proc/getDangerous()//This scales the TC assigned with the round population.
- ..()
- var/danger = GLOB.joined_player_list.len - SSticker.mode.syndicates.len
- danger = Ceiling(danger, 10)
- scaleTC(danger)
-
-/obj/machinery/computer/telecrystals/boss/proc/scaleTC(amt)//Its own proc, since it'll probably need a lot of tweaks for balance, use a fancier algorhithm, etc.
- storedcrystals += amt * NUKESCALINGMODIFIER
-
-/////////
-
-/obj/machinery/computer/telecrystals/boss/attack_hand(mob/user)
- if(..())
- return
- src.add_fingerprint(user)
- user.set_machine(src)
-
-
- var/dat = ""
- dat += "Scan for TC stations.
"
- dat += "[storedcrystals] telecrystals are available for distribution.
"
- dat += "
"
-
-
- for(var/obj/machinery/computer/telecrystals/uplinker/A in TCstations)
- dat += "[A.name] | "
- if(A.uplinkholder)
- dat += "[A.uplinkholder.hidden_uplink.telecrystals] telecrystals."
- if(storedcrystals)
- dat+= "
Add TC: 1 | 5 | 10 | All"
- dat += "
"
-
- if(TCstations.len && storedcrystals)
- dat += "
Evenly distribute remaining TC.
"
-
-
- for(var/entry in transferlog)
- dat += "[entry]
"
-
-
- var/datum/browser/popup = new(user, "computer", "Team Telecrystal Management Console", 700, 500)
- popup.set_content(dat)
- popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
- popup.open()
- return
-
-/obj/machinery/computer/telecrystals/boss/Topic(href, href_list)
- if(..())
- return
-
- if(href_list["scan"])
- scanUplinkers()
-
- if(href_list["give"])
- var/tcamt = text2num(href_list["give"])
- if(TCstations.len) // sanity
- var/obj/machinery/computer/telecrystals/uplinker/A = locate(href_list["target"]) in TCstations
- A.giveTC(tcamt)
-
- if(href_list["distrib"])
- var/sanity = 0
- while(storedcrystals && sanity < 100)
- for(var/obj/machinery/computer/telecrystals/uplinker/A in TCstations)
- A.giveTC(1,0)
- sanity++
- logTransfer("[src] evenly distributed telecrystals.")
-
- src.updateUsrDialog()
- return
-
-#undef NUKESCALINGMODIFIER
+#define NUKESCALINGMODIFIER 1
+
+GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","Echo","Foxtrot","Zero", "Niner"))
+
+/obj/machinery/computer/telecrystals
+ name = "\improper Telecrystal assignment station"
+ desc = "A device used to manage telecrystals during group operations. You shouldn't be looking at this particular one..."
+ icon_state = "tcstation"
+ icon_keyboard = "tcstation_key"
+ icon_screen = "syndie"
+ clockwork = TRUE //it'd look weird, at least if ratvar ever got there
+ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
+
+ light_color = LIGHT_COLOR_RED
+
+/////////////////////////////////////////////
+/obj/machinery/computer/telecrystals/uplinker
+ name = "\improper Telecrystal upload/receive station"
+ desc = "A device used to manage telecrystals during group operations. To use, simply insert your uplink. With your uplink installed \
+ you can upload your telecrystals to the group's pool using the console, or be assigned additional telecrystals by your lieutenant."
+ var/obj/item/uplinkholder = null
+ var/obj/machinery/computer/telecrystals/boss/linkedboss = null
+
+/obj/machinery/computer/telecrystals/uplinker/Initialize()
+ ..()
+
+ var/ID = pick_n_take(GLOB.possible_uplinker_IDs)
+ if(!ID)
+ ID = rand(1,999)
+ name = "[name] [ID]"
+
+/obj/machinery/computer/telecrystals/uplinker/attackby(obj/item/O, mob/user, params)
+ if(uplinkholder)
+ to_chat(user, "The [src] already has an uplink in it.")
+ return
+ if(O.hidden_uplink)
+ var/obj/item/I = user.get_active_held_item()
+ if(!user.drop_item())
+ return
+ uplinkholder = I
+ I.loc = src
+ I.add_fingerprint(user)
+ update_icon()
+ updateUsrDialog()
+ else
+ to_chat(user, "The [O] doesn't appear to be an uplink...")
+
+/obj/machinery/computer/telecrystals/uplinker/update_icon()
+ ..()
+ if(uplinkholder)
+ add_overlay("[initial(icon_state)]-closed")
+
+/obj/machinery/computer/telecrystals/uplinker/proc/ejectuplink()
+ if(uplinkholder)
+ uplinkholder.loc = get_turf(src.loc)
+ uplinkholder = null
+ update_icon()
+
+/obj/machinery/computer/telecrystals/uplinker/proc/donateTC(amt, addLog = 1)
+ if(uplinkholder && linkedboss)
+ if(amt < 0)
+ linkedboss.storedcrystals += uplinkholder.hidden_uplink.telecrystals
+ if(addLog)
+ linkedboss.logTransfer("[src] donated [uplinkholder.hidden_uplink.telecrystals] telecrystals to [linkedboss].")
+ uplinkholder.hidden_uplink.telecrystals = 0
+ else if(amt <= uplinkholder.hidden_uplink.telecrystals)
+ uplinkholder.hidden_uplink.telecrystals -= amt
+ linkedboss.storedcrystals += amt
+ if(addLog)
+ linkedboss.logTransfer("[src] donated [amt] telecrystals to [linkedboss].")
+
+/obj/machinery/computer/telecrystals/uplinker/proc/giveTC(amt, addLog = 1)
+ if(uplinkholder && linkedboss)
+ if(amt < 0)
+ uplinkholder.hidden_uplink.telecrystals += linkedboss.storedcrystals
+ if(addLog)
+ linkedboss.logTransfer("[src] received [linkedboss.storedcrystals] telecrystals from [linkedboss].")
+ linkedboss.storedcrystals = 0
+ else if(amt <= linkedboss.storedcrystals)
+ uplinkholder.hidden_uplink.telecrystals += amt
+ linkedboss.storedcrystals -= amt
+ if(addLog)
+ linkedboss.logTransfer("[src] received [amt] telecrystals from [linkedboss].")
+
+///////
+
+/obj/machinery/computer/telecrystals/uplinker/attack_hand(mob/user)
+ if(..())
+ return
+ src.add_fingerprint(user)
+ user.set_machine(src)
+
+ var/dat = ""
+ if(linkedboss)
+ dat += "[linkedboss] has [linkedboss.storedcrystals] telecrystals available for distribution.
"
+ else
+ dat += "No linked management consoles detected. Scan for uplink stations using the management console.
"
+
+ if(uplinkholder)
+ dat += "[uplinkholder.hidden_uplink.telecrystals] telecrystals remain in this uplink.
"
+ if(linkedboss)
+ dat += "Donate TC: 1 | 5 | All"
+ dat += "
Eject Uplink"
+
+
+ var/datum/browser/popup = new(user, "computer", "Telecrystal Upload/Receive Station", 700, 500)
+ popup.set_content(dat)
+ popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
+ popup.open()
+ return
+
+/obj/machinery/computer/telecrystals/uplinker/Topic(href, href_list)
+ if(..())
+ return
+
+ if(href_list["donate"])
+ var/tcamt = text2num(href_list["donate"])
+ donateTC(tcamt)
+
+ if(href_list["eject"])
+ ejectuplink()
+
+ src.updateUsrDialog()
+
+
+/////////////////////////////////////////
+/obj/machinery/computer/telecrystals/boss
+ name = "team Telecrystal management console"
+ desc = "A device used to manage telecrystals during group operations. To use, simply initialize the machine by scanning for nearby uplink stations. \
+ Once the consoles are linked up, you can assign any telecrystals amongst your operatives; be they donated by your agents or rationed to the squad \
+ based on the danger rating of the mission."
+ icon_state = "computer"
+ icon_screen = "tcboss"
+ icon_keyboard = "syndie_key"
+ var/virgin = 1
+ var/scanrange = 10
+ var/storedcrystals = 0
+ var/list/TCstations = list()
+ var/list/transferlog = list()
+
+/obj/machinery/computer/telecrystals/boss/proc/logTransfer(logmessage)
+ transferlog += ("[worldtime2text()] [logmessage]")
+
+/obj/machinery/computer/telecrystals/boss/proc/scanUplinkers()
+ for(var/obj/machinery/computer/telecrystals/uplinker/A in urange(scanrange, src.loc))
+ if(!A.linkedboss)
+ TCstations += A
+ A.linkedboss = src
+ if(virgin)
+ getDangerous()
+ virgin = 0
+
+/obj/machinery/computer/telecrystals/boss/proc/getDangerous()//This scales the TC assigned with the round population.
+ ..()
+ var/danger = GLOB.joined_player_list.len - SSticker.mode.syndicates.len
+ danger = Ceiling(danger, 10)
+ scaleTC(danger)
+
+/obj/machinery/computer/telecrystals/boss/proc/scaleTC(amt)//Its own proc, since it'll probably need a lot of tweaks for balance, use a fancier algorhithm, etc.
+ storedcrystals += amt * NUKESCALINGMODIFIER
+
+/////////
+
+/obj/machinery/computer/telecrystals/boss/attack_hand(mob/user)
+ if(..())
+ return
+ src.add_fingerprint(user)
+ user.set_machine(src)
+
+
+ var/dat = ""
+ dat += "Scan for TC stations.
"
+ dat += "[storedcrystals] telecrystals are available for distribution.
"
+ dat += "
"
+
+
+ for(var/obj/machinery/computer/telecrystals/uplinker/A in TCstations)
+ dat += "[A.name] | "
+ if(A.uplinkholder)
+ dat += "[A.uplinkholder.hidden_uplink.telecrystals] telecrystals."
+ if(storedcrystals)
+ dat+= "
Add TC: 1 | 5 | 10 | All"
+ dat += "
"
+
+ if(TCstations.len && storedcrystals)
+ dat += "
Evenly distribute remaining TC.
"
+
+
+ for(var/entry in transferlog)
+ dat += "[entry]
"
+
+
+ var/datum/browser/popup = new(user, "computer", "Team Telecrystal Management Console", 700, 500)
+ popup.set_content(dat)
+ popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
+ popup.open()
+ return
+
+/obj/machinery/computer/telecrystals/boss/Topic(href, href_list)
+ if(..())
+ return
+
+ if(href_list["scan"])
+ scanUplinkers()
+
+ if(href_list["give"])
+ var/tcamt = text2num(href_list["give"])
+ if(TCstations.len) // sanity
+ var/obj/machinery/computer/telecrystals/uplinker/A = locate(href_list["target"]) in TCstations
+ A.giveTC(tcamt)
+
+ if(href_list["distrib"])
+ var/sanity = 0
+ while(storedcrystals && sanity < 100)
+ for(var/obj/machinery/computer/telecrystals/uplinker/A in TCstations)
+ A.giveTC(1,0)
+ sanity++
+ logTransfer("[src] evenly distributed telecrystals.")
+
+ src.updateUsrDialog()
+ return
+
+#undef NUKESCALINGMODIFIER
diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm
index d04f88a9e7..1d7d9072c9 100644
--- a/code/game/mecha/equipment/weapons/weapons.dm
+++ b/code/game/mecha/equipment/weapons/weapons.dm
@@ -1,435 +1,435 @@
-/obj/item/mecha_parts/mecha_equipment/weapon
- name = "mecha weapon"
- range = RANGED
- origin_tech = "materials=3;combat=3"
- var/projectile
- var/fire_sound
- var/projectiles_per_shot = 1
- var/variance = 0
- var/randomspread = 0 //use random spread for machineguns, instead of shotgun scatter
- var/projectile_delay = 0
- var/firing_effect_type = /obj/effect/overlay/temp/dir_setting/firing_effect //the visual effect appearing when the weapon is fired.
-
-/obj/item/mecha_parts/mecha_equipment/weapon/can_attach(obj/mecha/combat/M)
- if(..())
- if(istype(M))
- return 1
- return 0
-
-/obj/item/mecha_parts/mecha_equipment/weapon/proc/get_shot_amount()
- return projectiles_per_shot
-
-/obj/item/mecha_parts/mecha_equipment/weapon/action(atom/target, params)
- if(!action_checks(target))
- return 0
-
- var/turf/curloc = get_turf(chassis)
- var/turf/targloc = get_turf(target)
- if (!targloc || !istype(targloc) || !curloc)
- return 0
- if (targloc == curloc)
- return 0
-
- set_ready_state(0)
- for(var/i=1 to get_shot_amount())
- var/obj/item/projectile/A = new projectile(curloc)
- A.firer = chassis.occupant
- A.original = target
- A.current = curloc
- if(!A.suppressed && firing_effect_type)
- new firing_effect_type(get_turf(src), chassis.dir)
-
-
- var/spread = 0
- if(variance)
- if(randomspread)
- spread = round((rand() - 0.5) * variance)
- else
- spread = round((i / projectiles_per_shot - 0.5) * variance)
- A.preparePixelProjectile(target, targloc, chassis.occupant, params, spread)
-
- A.fire()
- playsound(chassis, fire_sound, 50, 1)
-
- sleep(max(0, projectile_delay))
-
- chassis.log_message("Fired from [src.name], targeting [target].")
- return 1
-
-
-//Base energy weapon type
-/obj/item/mecha_parts/mecha_equipment/weapon/energy
- name = "general energy weapon"
- firing_effect_type = /obj/effect/overlay/temp/dir_setting/firing_effect/energy
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/get_shot_amount()
- return min(round(chassis.cell.charge / energy_drain), projectiles_per_shot)
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/start_cooldown()
- set_ready_state(0)
- chassis.use_power(energy_drain*get_shot_amount())
- addtimer(CALLBACK(src, .proc/set_ready_state, 1), equip_cooldown)
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser
- equip_cooldown = 8
- name = "\improper CH-PS \"Immolator\" laser"
- desc = "A weapon for combat exosuits. Shoots basic lasers."
- icon_state = "mecha_laser"
- origin_tech = "magnets=3;combat=3;engineering=3"
- energy_drain = 30
- projectile = /obj/item/projectile/beam/laser
- fire_sound = 'sound/weapons/Laser.ogg'
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy
- equip_cooldown = 15
- name = "\improper CH-LC \"Solaris\" laser cannon"
- desc = "A weapon for combat exosuits. Shoots heavy lasers."
- icon_state = "mecha_laser"
- origin_tech = "magnets=4;combat=4;engineering=3"
- energy_drain = 60
- projectile = /obj/item/projectile/beam/laser/heavylaser
- fire_sound = 'sound/weapons/lasercannonfire.ogg'
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/ion
- equip_cooldown = 20
- name = "\improper MKIV ion heavy cannon"
- desc = "A weapon for combat exosuits. Shoots technology-disabling ion beams. Don't catch yourself in the blast!"
- icon_state = "mecha_ion"
- origin_tech = "materials=4;combat=5;magnets=4"
- energy_drain = 120
- projectile = /obj/item/projectile/ion
- fire_sound = 'sound/weapons/Laser.ogg'
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/tesla
- equip_cooldown = 35
- name = "\improper MKI Tesla Cannon"
- desc = "A weapon for combat exosuits. Fires bolts of electricity similar to the experimental tesla engine"
- icon_state = "mecha_ion"
- origin_tech = "materials=4;engineering=4;combat=6;magnets=6"
- energy_drain = 500
- projectile = /obj/item/projectile/energy/tesla/cannon
- fire_sound = 'sound/magic/lightningbolt.ogg'
-
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/pulse
- equip_cooldown = 30
- name = "eZ-13 MK2 heavy pulse rifle"
- desc = "A weapon for combat exosuits. Shoots powerful destructive blasts capable of demolishing obstacles."
- icon_state = "mecha_pulse"
- energy_drain = 120
- origin_tech = "materials=3;combat=6;powerstorage=4"
- projectile = /obj/item/projectile/beam/pulse/heavy
- fire_sound = 'sound/weapons/marauder.ogg'
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/plasma
- equip_cooldown = 10
- name = "217-D Heavy Plasma Cutter"
- desc = "A device that shoots resonant plasma bursts at extreme velocity. The blasts are capable of crushing rock and demolishing solid obstacles."
- icon_state = "mecha_plasmacutter"
- item_state = "plasmacutter"
- energy_drain = 30
- origin_tech = "materials=3;plasmatech=4;engineering=3"
- projectile = /obj/item/projectile/plasma/adv/mech
- fire_sound = 'sound/weapons/plasma_cutter.ogg'
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/plasma/can_attach(obj/mecha/working/M)
- if(..()) //combat mech
- return 1
- else if(M.equipment.len < M.max_equip && istype(M))
- return 1
- return 0
-
-/obj/item/mecha_parts/mecha_equipment/weapon/energy/taser
- name = "\improper PBT \"Pacifier\" mounted taser"
- desc = "A weapon for combat exosuits. Shoots non-lethal stunning electrodes."
- icon_state = "mecha_taser"
- origin_tech = "combat=3"
- energy_drain = 20
- equip_cooldown = 8
- projectile = /obj/item/projectile/energy/electrode
- fire_sound = 'sound/weapons/Taser.ogg'
-
-
-/obj/item/mecha_parts/mecha_equipment/weapon/honker
- name = "\improper HoNkER BlAsT 5000"
- desc = "Equipment for clown exosuits. Spreads fun and joy to everyone around. Honk!"
- icon_state = "mecha_honker"
- energy_drain = 200
- equip_cooldown = 150
- range = MELEE|RANGED
-
-/obj/item/mecha_parts/mecha_equipment/weapon/honker/can_attach(obj/mecha/combat/honker/M)
- if(..())
- if(istype(M))
- return 1
- return 0
-
-/obj/item/mecha_parts/mecha_equipment/weapon/honker/action(target, params)
- if(!action_checks(target))
- return
- playsound(chassis, 'sound/items/AirHorn.ogg', 100, 1)
- chassis.occupant_message("HONK")
- for(var/mob/living/carbon/M in ohearers(6, chassis))
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(istype(H.ears, /obj/item/clothing/ears/earmuffs))
- continue
- to_chat(M, "HONK")
- M.SetSleeping(0)
- M.stuttering += 20
- M.adjustEarDamage(0, 30)
- M.Weaken(3)
- if(prob(30))
- M.Stun(10)
- M.Paralyse(4)
- else
- M.Jitter(500)
-
- log_message("Honked from [src.name]. HONK!")
- var/turf/T = get_turf(src)
- message_admins("[ADMIN_LOOKUPFLW(chassis.occupant)] used a Mecha Honker in [ADMIN_COORDJMP(T)]",0,1)
- log_game("[chassis.occupant.ckey]([chassis.occupant]) used a Mecha Honker in [COORD(T)]")
- return 1
-
-
-//Base ballistic weapon type
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic
- name = "general ballisic weapon"
- fire_sound = 'sound/weapons/Gunshot.ogg'
- var/projectiles
- var/projectile_energy_cost
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/get_shot_amount()
- return min(projectiles, projectiles_per_shot)
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/action_checks(target)
- if(!..())
- return 0
- if(projectiles <= 0)
- return 0
- return 1
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/get_equip_info()
- return "[..()] \[[src.projectiles]\][(src.projectiles < initial(src.projectiles))?" - Rearm":null]"
-
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/rearm()
- if(projectiles < initial(projectiles))
- var/projectiles_to_add = initial(projectiles) - projectiles
- while(chassis.get_charge() >= projectile_energy_cost && projectiles_to_add)
- projectiles++
- projectiles_to_add--
- chassis.use_power(projectile_energy_cost)
- send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info())
- log_message("Rearmed [src.name].")
- return 1
-
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/needs_rearm()
- . = !(projectiles > 0)
-
-
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/Topic(href, href_list)
- ..()
- if (href_list["rearm"])
- src.rearm()
- return
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/action(atom/target)
- if(..())
- projectiles -= get_shot_amount()
- send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info())
- return 1
-
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/carbine
- name = "\improper FNX-99 \"Hades\" Carbine"
- desc = "A weapon for combat exosuits. Shoots incendiary bullets."
- icon_state = "mecha_carbine"
- origin_tech = "materials=4;combat=4"
- equip_cooldown = 10
- projectile = /obj/item/projectile/bullet/incendiary/shell
- projectiles = 24
- projectile_energy_cost = 15
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/silenced
- name = "\improper S.H.H. \"Quietus\" Carbine"
- desc = "A weapon for combat exosuits. A mime invention, field tests have shown that targets cannot even scream before going down."
- fire_sound = 'sound/weapons/Gunshot_silenced.ogg'
- icon_state = "mecha_mime"
- equip_cooldown = 30
- projectile = /obj/item/projectile/bullet/mime
- projectiles = 6
- projectile_energy_cost = 50
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot
- name = "\improper LBX AC 10 \"Scattershot\""
- desc = "A weapon for combat exosuits. Shoots a spread of pellets."
- icon_state = "mecha_scatter"
- origin_tech = "combat=4"
- equip_cooldown = 20
- projectile = /obj/item/projectile/bullet/midbullet
- projectiles = 40
- projectile_energy_cost = 25
- projectiles_per_shot = 4
- variance = 25
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/lmg
- name = "\improper Ultra AC 2"
- desc = "A weapon for combat exosuits. Shoots a rapid, three shot burst."
- icon_state = "mecha_uac2"
- origin_tech = "combat=4"
- equip_cooldown = 10
- projectile = /obj/item/projectile/bullet/weakbullet3
- projectiles = 300
- projectile_energy_cost = 20
- projectiles_per_shot = 3
- variance = 6
- randomspread = 1
- projectile_delay = 2
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack
- name = "\improper SRM-8 missile rack"
- desc = "A weapon for combat exosuits. Shoots light explosive missiles."
- icon_state = "mecha_missilerack"
- origin_tech = "combat=5;materials=4;engineering=4"
- projectile = /obj/item/projectile/bullet/srmrocket
- fire_sound = 'sound/weapons/grenadelaunch.ogg'
- projectiles = 8
- projectile_energy_cost = 1000
- equip_cooldown = 60
-
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher
- var/missile_speed = 2
- var/missile_range = 30
- var/diags_first = FALSE
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/action(target)
- if(!action_checks(target))
- return
- var/obj/O = new projectile(chassis.loc)
- playsound(chassis, fire_sound, 50, 1)
- log_message("Launched a [O.name] from [name], targeting [target].")
- projectiles--
- proj_init(O)
- O.throw_at(target, missile_range, missile_speed, spin = 0, diagonals_first = diags_first)
- return 1
-
-//used for projectile initilisation (priming flashbang) and additional logging
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/proc/proj_init(var/obj/O)
- return
-
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang
- name = "\improper SGL-6 grenade launcher"
- desc = "A weapon for combat exosuits. Launches primed flashbangs."
- icon_state = "mecha_grenadelnchr"
- origin_tech = "combat=4;engineering=4"
- projectile = /obj/item/weapon/grenade/flashbang
- fire_sound = 'sound/weapons/grenadelaunch.ogg'
- projectiles = 6
- missile_speed = 1.5
- projectile_energy_cost = 800
- equip_cooldown = 60
- var/det_time = 20
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang/proj_init(var/obj/item/weapon/grenade/flashbang/F)
- var/turf/T = get_turf(src)
- message_admins("[ADMIN_LOOKUPFLW(chassis.occupant)] fired a [src] in [ADMIN_COORDJMP(T)]",0,1)
- log_game("[key_name(chassis.occupant)] fired a [src] [COORD(T)]")
- addtimer(CALLBACK(F, /obj/item/weapon/grenade/flashbang.proc/prime), det_time)
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang/clusterbang //Because I am a heartless bastard -Sieve //Heartless? for making the poor man's honkblast? - Kaze
- name = "\improper SOB-3 grenade launcher"
- desc = "A weapon for combat exosuits. Launches primed clusterbangs. You monster."
- origin_tech = "combat=4;materials=4"
- projectiles = 3
- projectile = /obj/item/weapon/grenade/clusterbuster
- projectile_energy_cost = 1600 //getting off cheap seeing as this is 3 times the flashbangs held in the grenade launcher.
- equip_cooldown = 90
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar
- name = "banana mortar"
- desc = "Equipment for clown exosuits. Launches banana peels."
- icon_state = "mecha_bananamrtr"
- projectile = /obj/item/weapon/grown/bananapeel
- fire_sound = 'sound/items/bikehorn.ogg'
- projectiles = 15
- missile_speed = 1.5
- projectile_energy_cost = 100
- equip_cooldown = 20
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar/can_attach(obj/mecha/combat/honker/M)
- if(..())
- if(istype(M))
- return 1
- return 0
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/mousetrap_mortar
- name = "mousetrap mortar"
- desc = "Equipment for clown exosuits. Launches armed mousetraps."
- icon_state = "mecha_mousetrapmrtr"
- projectile = /obj/item/device/assembly/mousetrap/armed
- fire_sound = 'sound/items/bikehorn.ogg'
- projectiles = 15
- missile_speed = 1.5
- projectile_energy_cost = 100
- equip_cooldown = 10
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/mousetrap_mortar/can_attach(obj/mecha/combat/honker/M)
- if(..())
- if(istype(M))
- return 1
- return 0
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/mousetrap_mortar/proj_init(var/obj/item/device/assembly/mousetrap/armed/M)
- M.secured = 1
-
-
-//Classic extending punching glove, but weaponised!
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove
- name = "\improper Oingo Boingo Punch-face"
- desc = "Equipment for clown exosuits. Delivers fun right to your face!"
- icon_state = "mecha_punching_glove"
- energy_drain = 250
- equip_cooldown = 20
- range = MELEE|RANGED
- missile_range = 5
- projectile = /obj/item/punching_glove
- fire_sound = 'sound/items/bikehorn.ogg'
- projectiles = 10
- projectile_energy_cost = 500
- diags_first = TRUE
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/can_attach(obj/mecha/combat/honker/M)
- if(..())
- if(istype(M))
- return 1
- return 0
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/action(target)
- . = ..()
- if(.)
- chassis.occupant_message("HONK")
-
-/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/proj_init(obj/item/punching_glove/PG)
- if(!istype(PG))
- return
- //has to be low sleep or it looks weird, the beam doesn't exist for very long so it's a non-issue
- chassis.Beam(PG, icon_state = "chain", time = missile_range * 20, maxdistance = missile_range + 2, beam_sleep_time = 1)
-
-/obj/item/punching_glove
- name = "punching glove"
- desc = "INCOMING HONKS"
- throwforce = 35
- icon_state = "punching_glove"
-
-/obj/item/punching_glove/throw_impact(atom/hit_atom)
- if(!..())
- if(istype(hit_atom, /atom/movable))
- var/atom/movable/AM = hit_atom
- AM.throw_at(get_edge_target_turf(AM,get_dir(src, AM)), 7, 2)
- qdel(src)
-
+/obj/item/mecha_parts/mecha_equipment/weapon
+ name = "mecha weapon"
+ range = RANGED
+ origin_tech = "materials=3;combat=3"
+ var/projectile
+ var/fire_sound
+ var/projectiles_per_shot = 1
+ var/variance = 0
+ var/randomspread = 0 //use random spread for machineguns, instead of shotgun scatter
+ var/projectile_delay = 0
+ var/firing_effect_type = /obj/effect/overlay/temp/dir_setting/firing_effect //the visual effect appearing when the weapon is fired.
+
+/obj/item/mecha_parts/mecha_equipment/weapon/can_attach(obj/mecha/combat/M)
+ if(..())
+ if(istype(M))
+ return 1
+ return 0
+
+/obj/item/mecha_parts/mecha_equipment/weapon/proc/get_shot_amount()
+ return projectiles_per_shot
+
+/obj/item/mecha_parts/mecha_equipment/weapon/action(atom/target, params)
+ if(!action_checks(target))
+ return 0
+
+ var/turf/curloc = get_turf(chassis)
+ var/turf/targloc = get_turf(target)
+ if (!targloc || !istype(targloc) || !curloc)
+ return 0
+ if (targloc == curloc)
+ return 0
+
+ set_ready_state(0)
+ for(var/i=1 to get_shot_amount())
+ var/obj/item/projectile/A = new projectile(curloc)
+ A.firer = chassis.occupant
+ A.original = target
+ A.current = curloc
+ if(!A.suppressed && firing_effect_type)
+ new firing_effect_type(get_turf(src), chassis.dir)
+
+
+ var/spread = 0
+ if(variance)
+ if(randomspread)
+ spread = round((rand() - 0.5) * variance)
+ else
+ spread = round((i / projectiles_per_shot - 0.5) * variance)
+ A.preparePixelProjectile(target, targloc, chassis.occupant, params, spread)
+
+ A.fire()
+ playsound(chassis, fire_sound, 50, 1)
+
+ sleep(max(0, projectile_delay))
+
+ chassis.log_message("Fired from [src.name], targeting [target].")
+ return 1
+
+
+//Base energy weapon type
+/obj/item/mecha_parts/mecha_equipment/weapon/energy
+ name = "general energy weapon"
+ firing_effect_type = /obj/effect/overlay/temp/dir_setting/firing_effect/energy
+
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/get_shot_amount()
+ return min(round(chassis.cell.charge / energy_drain), projectiles_per_shot)
+
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/start_cooldown()
+ set_ready_state(0)
+ chassis.use_power(energy_drain*get_shot_amount())
+ addtimer(CALLBACK(src, .proc/set_ready_state, 1), equip_cooldown)
+
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser
+ equip_cooldown = 8
+ name = "\improper CH-PS \"Immolator\" laser"
+ desc = "A weapon for combat exosuits. Shoots basic lasers."
+ icon_state = "mecha_laser"
+ origin_tech = "magnets=3;combat=3;engineering=3"
+ energy_drain = 30
+ projectile = /obj/item/projectile/beam/laser
+ fire_sound = 'sound/weapons/Laser.ogg'
+
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy
+ equip_cooldown = 15
+ name = "\improper CH-LC \"Solaris\" laser cannon"
+ desc = "A weapon for combat exosuits. Shoots heavy lasers."
+ icon_state = "mecha_laser"
+ origin_tech = "magnets=4;combat=4;engineering=3"
+ energy_drain = 60
+ projectile = /obj/item/projectile/beam/laser/heavylaser
+ fire_sound = 'sound/weapons/lasercannonfire.ogg'
+
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/ion
+ equip_cooldown = 20
+ name = "\improper MKIV ion heavy cannon"
+ desc = "A weapon for combat exosuits. Shoots technology-disabling ion beams. Don't catch yourself in the blast!"
+ icon_state = "mecha_ion"
+ origin_tech = "materials=4;combat=5;magnets=4"
+ energy_drain = 120
+ projectile = /obj/item/projectile/ion
+ fire_sound = 'sound/weapons/Laser.ogg'
+
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/tesla
+ equip_cooldown = 35
+ name = "\improper MKI Tesla Cannon"
+ desc = "A weapon for combat exosuits. Fires bolts of electricity similar to the experimental tesla engine"
+ icon_state = "mecha_ion"
+ origin_tech = "materials=4;engineering=4;combat=6;magnets=6"
+ energy_drain = 500
+ projectile = /obj/item/projectile/energy/tesla/cannon
+ fire_sound = 'sound/magic/lightningbolt.ogg'
+
+
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/pulse
+ equip_cooldown = 30
+ name = "eZ-13 MK2 heavy pulse rifle"
+ desc = "A weapon for combat exosuits. Shoots powerful destructive blasts capable of demolishing obstacles."
+ icon_state = "mecha_pulse"
+ energy_drain = 120
+ origin_tech = "materials=3;combat=6;powerstorage=4"
+ projectile = /obj/item/projectile/beam/pulse/heavy
+ fire_sound = 'sound/weapons/marauder.ogg'
+
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/plasma
+ equip_cooldown = 10
+ name = "217-D Heavy Plasma Cutter"
+ desc = "A device that shoots resonant plasma bursts at extreme velocity. The blasts are capable of crushing rock and demolishing solid obstacles."
+ icon_state = "mecha_plasmacutter"
+ item_state = "plasmacutter"
+ energy_drain = 30
+ origin_tech = "materials=3;plasmatech=4;engineering=3"
+ projectile = /obj/item/projectile/plasma/adv/mech
+ fire_sound = 'sound/weapons/plasma_cutter.ogg'
+
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/plasma/can_attach(obj/mecha/working/M)
+ if(..()) //combat mech
+ return 1
+ else if(M.equipment.len < M.max_equip && istype(M))
+ return 1
+ return 0
+
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/taser
+ name = "\improper PBT \"Pacifier\" mounted taser"
+ desc = "A weapon for combat exosuits. Shoots non-lethal stunning electrodes."
+ icon_state = "mecha_taser"
+ origin_tech = "combat=3"
+ energy_drain = 20
+ equip_cooldown = 8
+ projectile = /obj/item/projectile/energy/electrode
+ fire_sound = 'sound/weapons/Taser.ogg'
+
+
+/obj/item/mecha_parts/mecha_equipment/weapon/honker
+ name = "\improper HoNkER BlAsT 5000"
+ desc = "Equipment for clown exosuits. Spreads fun and joy to everyone around. Honk!"
+ icon_state = "mecha_honker"
+ energy_drain = 200
+ equip_cooldown = 150
+ range = MELEE|RANGED
+
+/obj/item/mecha_parts/mecha_equipment/weapon/honker/can_attach(obj/mecha/combat/honker/M)
+ if(..())
+ if(istype(M))
+ return 1
+ return 0
+
+/obj/item/mecha_parts/mecha_equipment/weapon/honker/action(target, params)
+ if(!action_checks(target))
+ return
+ playsound(chassis, 'sound/items/AirHorn.ogg', 100, 1)
+ chassis.occupant_message("HONK")
+ for(var/mob/living/carbon/M in ohearers(6, chassis))
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ if(istype(H.ears, /obj/item/clothing/ears/earmuffs))
+ continue
+ to_chat(M, "HONK")
+ M.SetSleeping(0)
+ M.stuttering += 20
+ M.adjustEarDamage(0, 30)
+ M.Weaken(3)
+ if(prob(30))
+ M.Stun(10)
+ M.Paralyse(4)
+ else
+ M.Jitter(500)
+
+ log_message("Honked from [src.name]. HONK!")
+ var/turf/T = get_turf(src)
+ message_admins("[ADMIN_LOOKUPFLW(chassis.occupant)] used a Mecha Honker in [ADMIN_COORDJMP(T)]",0,1)
+ log_game("[chassis.occupant.ckey]([chassis.occupant]) used a Mecha Honker in [COORD(T)]")
+ return 1
+
+
+//Base ballistic weapon type
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic
+ name = "general ballisic weapon"
+ fire_sound = 'sound/weapons/Gunshot.ogg'
+ var/projectiles
+ var/projectile_energy_cost
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/get_shot_amount()
+ return min(projectiles, projectiles_per_shot)
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/action_checks(target)
+ if(!..())
+ return 0
+ if(projectiles <= 0)
+ return 0
+ return 1
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/get_equip_info()
+ return "[..()] \[[src.projectiles]\][(src.projectiles < initial(src.projectiles))?" - Rearm":null]"
+
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/rearm()
+ if(projectiles < initial(projectiles))
+ var/projectiles_to_add = initial(projectiles) - projectiles
+ while(chassis.get_charge() >= projectile_energy_cost && projectiles_to_add)
+ projectiles++
+ projectiles_to_add--
+ chassis.use_power(projectile_energy_cost)
+ send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info())
+ log_message("Rearmed [src.name].")
+ return 1
+
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/needs_rearm()
+ . = !(projectiles > 0)
+
+
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/Topic(href, href_list)
+ ..()
+ if (href_list["rearm"])
+ src.rearm()
+ return
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/action(atom/target)
+ if(..())
+ projectiles -= get_shot_amount()
+ send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info())
+ return 1
+
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/carbine
+ name = "\improper FNX-99 \"Hades\" Carbine"
+ desc = "A weapon for combat exosuits. Shoots incendiary bullets."
+ icon_state = "mecha_carbine"
+ origin_tech = "materials=4;combat=4"
+ equip_cooldown = 10
+ projectile = /obj/item/projectile/bullet/incendiary/shell
+ projectiles = 24
+ projectile_energy_cost = 15
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/silenced
+ name = "\improper S.H.H. \"Quietus\" Carbine"
+ desc = "A weapon for combat exosuits. A mime invention, field tests have shown that targets cannot even scream before going down."
+ fire_sound = 'sound/weapons/Gunshot_silenced.ogg'
+ icon_state = "mecha_mime"
+ equip_cooldown = 30
+ projectile = /obj/item/projectile/bullet/mime
+ projectiles = 6
+ projectile_energy_cost = 50
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot
+ name = "\improper LBX AC 10 \"Scattershot\""
+ desc = "A weapon for combat exosuits. Shoots a spread of pellets."
+ icon_state = "mecha_scatter"
+ origin_tech = "combat=4"
+ equip_cooldown = 20
+ projectile = /obj/item/projectile/bullet/midbullet
+ projectiles = 40
+ projectile_energy_cost = 25
+ projectiles_per_shot = 4
+ variance = 25
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/lmg
+ name = "\improper Ultra AC 2"
+ desc = "A weapon for combat exosuits. Shoots a rapid, three shot burst."
+ icon_state = "mecha_uac2"
+ origin_tech = "combat=4"
+ equip_cooldown = 10
+ projectile = /obj/item/projectile/bullet/weakbullet3
+ projectiles = 300
+ projectile_energy_cost = 20
+ projectiles_per_shot = 3
+ variance = 6
+ randomspread = 1
+ projectile_delay = 2
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack
+ name = "\improper SRM-8 missile rack"
+ desc = "A weapon for combat exosuits. Shoots light explosive missiles."
+ icon_state = "mecha_missilerack"
+ origin_tech = "combat=5;materials=4;engineering=4"
+ projectile = /obj/item/projectile/bullet/srmrocket
+ fire_sound = 'sound/weapons/grenadelaunch.ogg'
+ projectiles = 8
+ projectile_energy_cost = 1000
+ equip_cooldown = 60
+
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher
+ var/missile_speed = 2
+ var/missile_range = 30
+ var/diags_first = FALSE
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/action(target)
+ if(!action_checks(target))
+ return
+ var/obj/O = new projectile(chassis.loc)
+ playsound(chassis, fire_sound, 50, 1)
+ log_message("Launched a [O.name] from [name], targeting [target].")
+ projectiles--
+ proj_init(O)
+ O.throw_at(target, missile_range, missile_speed, spin = 0, diagonals_first = diags_first)
+ return 1
+
+//used for projectile initilisation (priming flashbang) and additional logging
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/proc/proj_init(var/obj/O)
+ return
+
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang
+ name = "\improper SGL-6 grenade launcher"
+ desc = "A weapon for combat exosuits. Launches primed flashbangs."
+ icon_state = "mecha_grenadelnchr"
+ origin_tech = "combat=4;engineering=4"
+ projectile = /obj/item/weapon/grenade/flashbang
+ fire_sound = 'sound/weapons/grenadelaunch.ogg'
+ projectiles = 6
+ missile_speed = 1.5
+ projectile_energy_cost = 800
+ equip_cooldown = 60
+ var/det_time = 20
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang/proj_init(var/obj/item/weapon/grenade/flashbang/F)
+ var/turf/T = get_turf(src)
+ message_admins("[ADMIN_LOOKUPFLW(chassis.occupant)] fired a [src] in [ADMIN_COORDJMP(T)]",0,1)
+ log_game("[key_name(chassis.occupant)] fired a [src] [COORD(T)]")
+ addtimer(CALLBACK(F, /obj/item/weapon/grenade/flashbang.proc/prime), det_time)
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/flashbang/clusterbang //Because I am a heartless bastard -Sieve //Heartless? for making the poor man's honkblast? - Kaze
+ name = "\improper SOB-3 grenade launcher"
+ desc = "A weapon for combat exosuits. Launches primed clusterbangs. You monster."
+ origin_tech = "combat=4;materials=4"
+ projectiles = 3
+ projectile = /obj/item/weapon/grenade/clusterbuster
+ projectile_energy_cost = 1600 //getting off cheap seeing as this is 3 times the flashbangs held in the grenade launcher.
+ equip_cooldown = 90
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar
+ name = "banana mortar"
+ desc = "Equipment for clown exosuits. Launches banana peels."
+ icon_state = "mecha_bananamrtr"
+ projectile = /obj/item/weapon/grown/bananapeel
+ fire_sound = 'sound/items/bikehorn.ogg'
+ projectiles = 15
+ missile_speed = 1.5
+ projectile_energy_cost = 100
+ equip_cooldown = 20
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/banana_mortar/can_attach(obj/mecha/combat/honker/M)
+ if(..())
+ if(istype(M))
+ return 1
+ return 0
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/mousetrap_mortar
+ name = "mousetrap mortar"
+ desc = "Equipment for clown exosuits. Launches armed mousetraps."
+ icon_state = "mecha_mousetrapmrtr"
+ projectile = /obj/item/device/assembly/mousetrap/armed
+ fire_sound = 'sound/items/bikehorn.ogg'
+ projectiles = 15
+ missile_speed = 1.5
+ projectile_energy_cost = 100
+ equip_cooldown = 10
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/mousetrap_mortar/can_attach(obj/mecha/combat/honker/M)
+ if(..())
+ if(istype(M))
+ return 1
+ return 0
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/mousetrap_mortar/proj_init(var/obj/item/device/assembly/mousetrap/armed/M)
+ M.secured = 1
+
+
+//Classic extending punching glove, but weaponised!
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove
+ name = "\improper Oingo Boingo Punch-face"
+ desc = "Equipment for clown exosuits. Delivers fun right to your face!"
+ icon_state = "mecha_punching_glove"
+ energy_drain = 250
+ equip_cooldown = 20
+ range = MELEE|RANGED
+ missile_range = 5
+ projectile = /obj/item/punching_glove
+ fire_sound = 'sound/items/bikehorn.ogg'
+ projectiles = 10
+ projectile_energy_cost = 500
+ diags_first = TRUE
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/can_attach(obj/mecha/combat/honker/M)
+ if(..())
+ if(istype(M))
+ return 1
+ return 0
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/action(target)
+ . = ..()
+ if(.)
+ chassis.occupant_message("HONK")
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/launcher/punching_glove/proj_init(obj/item/punching_glove/PG)
+ if(!istype(PG))
+ return
+ //has to be low sleep or it looks weird, the beam doesn't exist for very long so it's a non-issue
+ chassis.Beam(PG, icon_state = "chain", time = missile_range * 20, maxdistance = missile_range + 2, beam_sleep_time = 1)
+
+/obj/item/punching_glove
+ name = "punching glove"
+ desc = "INCOMING HONKS"
+ throwforce = 35
+ icon_state = "punching_glove"
+
+/obj/item/punching_glove/throw_impact(atom/hit_atom)
+ if(!..())
+ if(istype(hit_atom, /atom/movable))
+ var/atom/movable/AM = hit_atom
+ AM.throw_at(get_edge_target_turf(AM,get_dir(src, AM)), 7, 2)
+ qdel(src)
+
diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm
index 2bb55410e1..5ce88f1c27 100644
--- a/code/game/objects/effects/landmarks.dm
+++ b/code/game/objects/effects/landmarks.dm
@@ -1,333 +1,333 @@
-/obj/effect/landmark
- name = "landmark"
- icon = 'icons/mob/screen_gen.dmi'
- icon_state = "x2"
- anchored = 1
- invisibility = INVISIBILITY_ABSTRACT
-
-/obj/effect/landmark/New()
- ..()
- tag = text("landmark*[]", name)
- GLOB.landmarks_list += src
-
-/obj/effect/landmark/Destroy()
- GLOB.landmarks_list -= src
- return ..()
-
-/obj/effect/landmark/start
- name = "start"
- icon = 'icons/mob/screen_gen.dmi'
- icon_state = "x"
- anchored = 1
-
-/obj/effect/landmark/start/New()
- GLOB.start_landmarks_list += src
- ..()
- if(name != "start")
- tag = "start*[name]"
-
-/obj/effect/landmark/start/Destroy()
- GLOB.start_landmarks_list -= src
- return ..()
-
-// START LANDMARKS FOLLOW. Don't change the names unless
-// you are refactoring shitty landmark code.
-
-/obj/effect/landmark/start/assistant
- name = "Assistant"
-
-/obj/effect/landmark/start/janitor
- name = "Janitor"
-
-/obj/effect/landmark/start/cargo_technician
- name = "Cargo Technician"
-
-/obj/effect/landmark/start/bartender
- name = "Bartender"
-
-/obj/effect/landmark/start/clown
- name = "Clown"
-
-/obj/effect/landmark/start/mime
- name = "Mime"
-
-/obj/effect/landmark/start/quartermaster
- name = "Quartermaster"
-
-/obj/effect/landmark/start/atmospheric_technician
- name = "Atmospheric Technician"
-
-/obj/effect/landmark/start/cook
- name = "Cook"
-
-/obj/effect/landmark/start/shaft_miner
- name = "Shaft Miner"
-
-/obj/effect/landmark/start/security_officer
- name = "Security Officer"
-
-/obj/effect/landmark/start/botanist
- name = "Botanist"
-
-/obj/effect/landmark/start/head_of_security
- name = "Head of Security"
-
-/obj/effect/landmark/start/ai
- name = "AI"
-
-/obj/effect/landmark/start/captain
- name = "Captain"
-
-/obj/effect/landmark/start/detective
- name = "Detective"
-
-/obj/effect/landmark/start/warden
- name = "Warden"
-
-/obj/effect/landmark/start/chief_engineer
- name = "Chief Engineer"
-
-/obj/effect/landmark/start/cyborg
- name = "Cyborg"
-
-/obj/effect/landmark/start/head_of_personnel
- name = "Head of Personnel"
-
-/obj/effect/landmark/start/librarian
- name = "Curator"
-
-/obj/effect/landmark/start/lawyer
- name = "Lawyer"
-
-/obj/effect/landmark/start/station_engineer
- name = "Station Engineer"
-
-/obj/effect/landmark/start/medical_doctor
- name = "Medical Doctor"
-
-/obj/effect/landmark/start/scientist
- name = "Scientist"
-
-/obj/effect/landmark/start/chemist
- name = "Chemist"
-
-/obj/effect/landmark/start/roboticist
- name = "Roboticist"
-
-/obj/effect/landmark/start/research_director
- name = "Research Director"
-
-/obj/effect/landmark/start/geneticist
- name = "Geneticist"
-
-/obj/effect/landmark/start/chief_medical_officer
- name = "Chief Medical Officer"
-
-/obj/effect/landmark/start/virologist
- name = "Virologist"
-
-/obj/effect/landmark/start/chaplain
- name = "Chaplain"
-
-//Department Security spawns
-
-/obj/effect/landmark/start/depsec
- name = "department_sec"
-
-/obj/effect/landmark/start/depsec/New()
- ..()
- GLOB.department_security_spawns += src
-
-/obj/effect/landmark/start/depsec/Destroy()
- GLOB.department_security_spawns -= src
- return ..()
-
-/obj/effect/landmark/start/depsec/supply
- name = "supply_sec"
-
-/obj/effect/landmark/start/depsec/medical
- name = "medical_sec"
-
-/obj/effect/landmark/start/depsec/engineering
- name = "engineering_sec"
-
-/obj/effect/landmark/start/depsec/science
- name = "science_sec"
-
-/obj/effect/landmark/start/wizard
- name = "wizard"
-
-/obj/effect/landmark/start/wizard/Initialize(mapload)
- ..()
- GLOB.wizardstart += loc
- qdel(src)
-
-/obj/effect/landmark/start/new_player
- name = "New Player"
-
-// Must be on New() rather than Initialize, because players will
-// join before SSatom initializes everything.
-/obj/effect/landmark/start/new_player/New(loc)
- ..()
- GLOB.newplayer_start += loc
-
-/obj/effect/landmark/start/new_player/Initialize(mapload)
- ..()
- qdel(src)
-
-
-
-/obj/effect/landmark/latejoin
- name = "JoinLate"
-
-/obj/effect/landmark/latejoin/Initialize(mapload)
- ..()
- GLOB.latejoin += loc
- qdel(src)
-
-// carp.
-/obj/effect/landmark/carpspawn
- name = "carpspawn"
-
-// lightsout.
-/obj/effect/landmark/lightsout
- name = "lightsout"
-
-// observer-start.
-/obj/effect/landmark/observer_start
- name = "Observer-Start"
-
-// revenant spawn.
-/obj/effect/landmark/revenantspawn
- name = "revnantspawn"
-
-// triple ais.
-/obj/effect/landmark/tripai
- name = "tripai"
-
-// marauder entry (XXX WTF IS MAURADER ENTRY???)
-
-/obj/effect/landmark/marauder_entry
- name = "Marauder Entry"
-
-// syndicate breach area (XXX I DON'T KNOW WHAT THIS IS EITHER)
-
-/obj/effect/landmark/syndicate_breach_area
- name = "Syndicate Breach Area"
-
-// teleport scroll landmark, XXX DOES THIS DO ANYTHING?
-/obj/effect/landmark/teleport_scroll
- name = "Teleport-Scroll"
-
-/obj/effect/landmark/syndicate_spawn
- name = "Syndicate-Spawn"
-
-// xenos.
-/obj/effect/landmark/xeno_spawn
- name = "xeno_spawn"
-
-/obj/effect/landmark/xeno_spawn/Initialize(mapload)
- ..()
- GLOB.xeno_spawn += loc
- qdel(src)
-
-// blobs.
-/obj/effect/landmark/blobstart
- name = "blobstart"
-
-/obj/effect/landmark/blobstart/Initialize(mapload)
- ..()
- GLOB.blobstart += loc
- qdel(src)
-
-/obj/effect/landmark/secequipment
- name = "secequipment"
-
-/obj/effect/landmark/secequipment/Initialize(mapload)
- ..()
- GLOB.secequipment += loc
- qdel(src)
-
-/obj/effect/landmark/prisonwarp
- name = "prisonwarp"
-
-/obj/effect/landmark/prisonwarp/Initialize(mapload)
- ..()
- GLOB.prisonwarp += loc
- qdel(src)
-
-/obj/effect/landmark/ert_spawn
- name = "Emergencyresponseteam"
-
-/obj/effect/landmark/ert_spawn/Initialize(mapload)
- ..()
- GLOB.emergencyresponseteamspawn += loc
- qdel(src)
-
-/obj/effect/landmark/holding_facility
- name = "Holding Facility"
-
-/obj/effect/landmark/holding_facility/Initialize(mapload)
- ..()
- GLOB.holdingfacility += loc
- qdel(src)
-
-/obj/effect/landmark/thunderdome/observe
- name = "tdomeobserve"
-
-/obj/effect/landmark/thunderdome/observe/Initialize(mapload)
- ..()
- GLOB.tdomeobserve += loc
- qdel(src)
-
-/obj/effect/landmark/thunderdome/one
- name = "tdome1"
-
-/obj/effect/landmark/thunderdome/one/Initialize(mapload)
- ..()
- GLOB.tdome1 += loc
- qdel(src)
-
-/obj/effect/landmark/thunderdome/two
- name = "tdome2"
-
-/obj/effect/landmark/thunderdome/two/Initialize(mapload)
- ..()
- GLOB.tdome2 += loc
- qdel(src)
-
-/obj/effect/landmark/thunderdome/admin
- name = "tdomeadmin"
-
-/obj/effect/landmark/thunderdome/admin/Initialize(mapload)
- ..()
- GLOB.tdomeadmin += loc
- qdel(src)
-
-//generic event spawns
-/obj/effect/landmark/event_spawn
- name = "generic event spawn"
- icon_state = "x4"
-
-
-/obj/effect/landmark/event_spawn/New()
- ..()
- GLOB.generic_event_spawns += src
-
-/obj/effect/landmark/event_spawn/Destroy()
- GLOB.generic_event_spawns -= src
- return ..()
-
-/obj/effect/landmark/ruin
- var/datum/map_template/ruin/ruin_template
-
-/obj/effect/landmark/ruin/New(loc, my_ruin_template)
- name = "ruin_[GLOB.ruin_landmarks.len + 1]"
- ..(loc)
- ruin_template = my_ruin_template
- GLOB.ruin_landmarks |= src
-
-/obj/effect/landmark/ruin/Destroy()
- GLOB.ruin_landmarks -= src
- ruin_template = null
- . = ..()
+/obj/effect/landmark
+ name = "landmark"
+ icon = 'icons/mob/screen_gen.dmi'
+ icon_state = "x2"
+ anchored = 1
+ invisibility = INVISIBILITY_ABSTRACT
+
+/obj/effect/landmark/New()
+ ..()
+ tag = text("landmark*[]", name)
+ GLOB.landmarks_list += src
+
+/obj/effect/landmark/Destroy()
+ GLOB.landmarks_list -= src
+ return ..()
+
+/obj/effect/landmark/start
+ name = "start"
+ icon = 'icons/mob/screen_gen.dmi'
+ icon_state = "x"
+ anchored = 1
+
+/obj/effect/landmark/start/New()
+ GLOB.start_landmarks_list += src
+ ..()
+ if(name != "start")
+ tag = "start*[name]"
+
+/obj/effect/landmark/start/Destroy()
+ GLOB.start_landmarks_list -= src
+ return ..()
+
+// START LANDMARKS FOLLOW. Don't change the names unless
+// you are refactoring shitty landmark code.
+
+/obj/effect/landmark/start/assistant
+ name = "Assistant"
+
+/obj/effect/landmark/start/janitor
+ name = "Janitor"
+
+/obj/effect/landmark/start/cargo_technician
+ name = "Cargo Technician"
+
+/obj/effect/landmark/start/bartender
+ name = "Bartender"
+
+/obj/effect/landmark/start/clown
+ name = "Clown"
+
+/obj/effect/landmark/start/mime
+ name = "Mime"
+
+/obj/effect/landmark/start/quartermaster
+ name = "Quartermaster"
+
+/obj/effect/landmark/start/atmospheric_technician
+ name = "Atmospheric Technician"
+
+/obj/effect/landmark/start/cook
+ name = "Cook"
+
+/obj/effect/landmark/start/shaft_miner
+ name = "Shaft Miner"
+
+/obj/effect/landmark/start/security_officer
+ name = "Security Officer"
+
+/obj/effect/landmark/start/botanist
+ name = "Botanist"
+
+/obj/effect/landmark/start/head_of_security
+ name = "Head of Security"
+
+/obj/effect/landmark/start/ai
+ name = "AI"
+
+/obj/effect/landmark/start/captain
+ name = "Captain"
+
+/obj/effect/landmark/start/detective
+ name = "Detective"
+
+/obj/effect/landmark/start/warden
+ name = "Warden"
+
+/obj/effect/landmark/start/chief_engineer
+ name = "Chief Engineer"
+
+/obj/effect/landmark/start/cyborg
+ name = "Cyborg"
+
+/obj/effect/landmark/start/head_of_personnel
+ name = "Head of Personnel"
+
+/obj/effect/landmark/start/librarian
+ name = "Curator"
+
+/obj/effect/landmark/start/lawyer
+ name = "Lawyer"
+
+/obj/effect/landmark/start/station_engineer
+ name = "Station Engineer"
+
+/obj/effect/landmark/start/medical_doctor
+ name = "Medical Doctor"
+
+/obj/effect/landmark/start/scientist
+ name = "Scientist"
+
+/obj/effect/landmark/start/chemist
+ name = "Chemist"
+
+/obj/effect/landmark/start/roboticist
+ name = "Roboticist"
+
+/obj/effect/landmark/start/research_director
+ name = "Research Director"
+
+/obj/effect/landmark/start/geneticist
+ name = "Geneticist"
+
+/obj/effect/landmark/start/chief_medical_officer
+ name = "Chief Medical Officer"
+
+/obj/effect/landmark/start/virologist
+ name = "Virologist"
+
+/obj/effect/landmark/start/chaplain
+ name = "Chaplain"
+
+//Department Security spawns
+
+/obj/effect/landmark/start/depsec
+ name = "department_sec"
+
+/obj/effect/landmark/start/depsec/New()
+ ..()
+ GLOB.department_security_spawns += src
+
+/obj/effect/landmark/start/depsec/Destroy()
+ GLOB.department_security_spawns -= src
+ return ..()
+
+/obj/effect/landmark/start/depsec/supply
+ name = "supply_sec"
+
+/obj/effect/landmark/start/depsec/medical
+ name = "medical_sec"
+
+/obj/effect/landmark/start/depsec/engineering
+ name = "engineering_sec"
+
+/obj/effect/landmark/start/depsec/science
+ name = "science_sec"
+
+/obj/effect/landmark/start/wizard
+ name = "wizard"
+
+/obj/effect/landmark/start/wizard/Initialize(mapload)
+ ..()
+ GLOB.wizardstart += loc
+ qdel(src)
+
+/obj/effect/landmark/start/new_player
+ name = "New Player"
+
+// Must be on New() rather than Initialize, because players will
+// join before SSatom initializes everything.
+/obj/effect/landmark/start/new_player/New(loc)
+ ..()
+ GLOB.newplayer_start += loc
+
+/obj/effect/landmark/start/new_player/Initialize(mapload)
+ ..()
+ qdel(src)
+
+
+
+/obj/effect/landmark/latejoin
+ name = "JoinLate"
+
+/obj/effect/landmark/latejoin/Initialize(mapload)
+ ..()
+ GLOB.latejoin += loc
+ qdel(src)
+
+// carp.
+/obj/effect/landmark/carpspawn
+ name = "carpspawn"
+
+// lightsout.
+/obj/effect/landmark/lightsout
+ name = "lightsout"
+
+// observer-start.
+/obj/effect/landmark/observer_start
+ name = "Observer-Start"
+
+// revenant spawn.
+/obj/effect/landmark/revenantspawn
+ name = "revnantspawn"
+
+// triple ais.
+/obj/effect/landmark/tripai
+ name = "tripai"
+
+// marauder entry (XXX WTF IS MAURADER ENTRY???)
+
+/obj/effect/landmark/marauder_entry
+ name = "Marauder Entry"
+
+// syndicate breach area (XXX I DON'T KNOW WHAT THIS IS EITHER)
+
+/obj/effect/landmark/syndicate_breach_area
+ name = "Syndicate Breach Area"
+
+// teleport scroll landmark, XXX DOES THIS DO ANYTHING?
+/obj/effect/landmark/teleport_scroll
+ name = "Teleport-Scroll"
+
+/obj/effect/landmark/syndicate_spawn
+ name = "Syndicate-Spawn"
+
+// xenos.
+/obj/effect/landmark/xeno_spawn
+ name = "xeno_spawn"
+
+/obj/effect/landmark/xeno_spawn/Initialize(mapload)
+ ..()
+ GLOB.xeno_spawn += loc
+ qdel(src)
+
+// blobs.
+/obj/effect/landmark/blobstart
+ name = "blobstart"
+
+/obj/effect/landmark/blobstart/Initialize(mapload)
+ ..()
+ GLOB.blobstart += loc
+ qdel(src)
+
+/obj/effect/landmark/secequipment
+ name = "secequipment"
+
+/obj/effect/landmark/secequipment/Initialize(mapload)
+ ..()
+ GLOB.secequipment += loc
+ qdel(src)
+
+/obj/effect/landmark/prisonwarp
+ name = "prisonwarp"
+
+/obj/effect/landmark/prisonwarp/Initialize(mapload)
+ ..()
+ GLOB.prisonwarp += loc
+ qdel(src)
+
+/obj/effect/landmark/ert_spawn
+ name = "Emergencyresponseteam"
+
+/obj/effect/landmark/ert_spawn/Initialize(mapload)
+ ..()
+ GLOB.emergencyresponseteamspawn += loc
+ qdel(src)
+
+/obj/effect/landmark/holding_facility
+ name = "Holding Facility"
+
+/obj/effect/landmark/holding_facility/Initialize(mapload)
+ ..()
+ GLOB.holdingfacility += loc
+ qdel(src)
+
+/obj/effect/landmark/thunderdome/observe
+ name = "tdomeobserve"
+
+/obj/effect/landmark/thunderdome/observe/Initialize(mapload)
+ ..()
+ GLOB.tdomeobserve += loc
+ qdel(src)
+
+/obj/effect/landmark/thunderdome/one
+ name = "tdome1"
+
+/obj/effect/landmark/thunderdome/one/Initialize(mapload)
+ ..()
+ GLOB.tdome1 += loc
+ qdel(src)
+
+/obj/effect/landmark/thunderdome/two
+ name = "tdome2"
+
+/obj/effect/landmark/thunderdome/two/Initialize(mapload)
+ ..()
+ GLOB.tdome2 += loc
+ qdel(src)
+
+/obj/effect/landmark/thunderdome/admin
+ name = "tdomeadmin"
+
+/obj/effect/landmark/thunderdome/admin/Initialize(mapload)
+ ..()
+ GLOB.tdomeadmin += loc
+ qdel(src)
+
+//generic event spawns
+/obj/effect/landmark/event_spawn
+ name = "generic event spawn"
+ icon_state = "x4"
+
+
+/obj/effect/landmark/event_spawn/New()
+ ..()
+ GLOB.generic_event_spawns += src
+
+/obj/effect/landmark/event_spawn/Destroy()
+ GLOB.generic_event_spawns -= src
+ return ..()
+
+/obj/effect/landmark/ruin
+ var/datum/map_template/ruin/ruin_template
+
+/obj/effect/landmark/ruin/New(loc, my_ruin_template)
+ name = "ruin_[GLOB.ruin_landmarks.len + 1]"
+ ..(loc)
+ ruin_template = my_ruin_template
+ GLOB.ruin_landmarks |= src
+
+/obj/effect/landmark/ruin/Destroy()
+ GLOB.ruin_landmarks -= src
+ ruin_template = null
+ . = ..()
diff --git a/code/game/objects/effects/step_triggers.dm b/code/game/objects/effects/step_triggers.dm
index 6bd4db9a8d..8d59a03f02 100644
--- a/code/game/objects/effects/step_triggers.dm
+++ b/code/game/objects/effects/step_triggers.dm
@@ -183,9 +183,9 @@
if(!T)
return
- if(triggerer_only && ismob(A))
- var/mob/B = A
- B.playsound_local(T, sound, volume, freq_vary)
+ if(triggerer_only && ismob(A))
+ var/mob/B = A
+ B.playsound_local(T, sound, volume, freq_vary)
else
playsound(T, sound, volume, freq_vary, extra_range)
diff --git a/code/game/objects/items/devices/PDA/cart.dm b/code/game/objects/items/devices/PDA/cart.dm
index 4eb36f6fbd..60296fd4d5 100644
--- a/code/game/objects/items/devices/PDA/cart.dm
+++ b/code/game/objects/items/devices/PDA/cart.dm
@@ -1,787 +1,787 @@
-/obj/item/weapon/cartridge
- name = "generic cartridge"
- desc = "A data cartridge for portable microcomputers."
- icon = 'icons/obj/pda.dmi'
- icon_state = "cart"
- item_state = "electronic"
- w_class = WEIGHT_CLASS_TINY
-
- var/obj/item/radio/integrated/radio = null
- var/access_security = 0
- var/access_engine = 0
- var/access_atmos = 0
- var/access_medical = 0
- var/access_manifest = 0
- var/access_clown = 0
- var/access_mime = 0
- var/access_janitor = 0
-// var/access_flora = 0
- var/access_reagent_scanner = 0
- var/access_newscaster = 0
- var/access_remote_door = 0 //Control some blast doors remotely!!
- var/remote_door_id = ""
- var/access_status_display = 0
- var/access_quartermaster = 0
- var/access_hydroponics = 0
- var/access_dronephone = 0
- var/bot_access_flags = 0 //Bit flags. Selection: SEC_BOT|MULE_BOT|FLOOR_BOT|CLEAN_BOT|MED_BOT
- var/spam_enabled = 0 //Enables "Send to All" Option
-
- var/mode = null
- var/menu
- var/datum/data/record/active1 = null //General
- var/datum/data/record/active2 = null //Medical
- var/datum/data/record/active3 = null //Security
- var/obj/machinery/computer/monitor/powmonitor = null // Power Monitor
- var/list/powermonitors = list()
- var/message1 // used for status_displays
- var/message2
- var/list/stored_data = list()
- var/current_channel
-
- var/mob/living/simple_animal/bot/active_bot
- var/list/botlist = list()
-
-/obj/item/weapon/cartridge/engineering
- name = "\improper Power-ON cartridge"
- icon_state = "cart-e"
- access_engine = 1
- access_dronephone = 1
- bot_access_flags = FLOOR_BOT
-
-/obj/item/weapon/cartridge/atmos
- name = "\improper BreatheDeep cartridge"
- icon_state = "cart-a"
- access_atmos = 1
- access_dronephone = 1
- bot_access_flags = FLOOR_BOT
-
-/obj/item/weapon/cartridge/medical
- name = "\improper Med-U cartridge"
- icon_state = "cart-m"
- access_medical = 1
- bot_access_flags = MED_BOT
-
-/obj/item/weapon/cartridge/chemistry
- name = "\improper ChemWhiz cartridge"
- icon_state = "cart-chem"
- access_reagent_scanner = 1
- bot_access_flags = MED_BOT
-
-/obj/item/weapon/cartridge/security
- name = "\improper R.O.B.U.S.T. cartridge"
- icon_state = "cart-s"
- access_security = 1
- bot_access_flags = SEC_BOT
-
-/obj/item/weapon/cartridge/detective
- name = "\improper D.E.T.E.C.T. cartridge"
- icon_state = "cart-s"
- access_security = 1
- access_medical = 1
- access_manifest = 1
- bot_access_flags = SEC_BOT
-
-/obj/item/weapon/cartridge/janitor
- name = "\improper CustodiPRO cartridge"
- desc = "The ultimate in clean-room design."
- icon_state = "cart-j"
- access_janitor = 1
- access_dronephone = 1
- bot_access_flags = CLEAN_BOT
-
-/obj/item/weapon/cartridge/lawyer
- name = "\improper P.R.O.V.E. cartridge"
- icon_state = "cart-s"
- access_security = 1
- spam_enabled = 1
-
-/obj/item/weapon/cartridge/clown
- name = "\improper Honkworks 5.0 cartridge"
- icon_state = "cart-clown"
- access_clown = 1
- var/honk_charges = 5
-
-/obj/item/weapon/cartridge/mime
- name = "\improper Gestur-O 1000 cartridge"
- icon_state = "cart-mi"
- access_mime = 1
- var/mime_charges = 5
-
-/obj/item/weapon/cartridge/curator
- name = "\improper Lib-Tweet cartridge"
- icon_state = "cart-s"
- access_newscaster = 1
-
-/*
-/obj/item/weapon/cartridge/botanist
- name = "\improper Green Thumb v4.20 cartridge"
- icon_state = "cart-b"
- access_flora = 1
-*/
-
-/obj/item/weapon/cartridge/roboticist
- name = "\improper B.O.O.P. Remote Control cartridge"
- desc = "Packed with heavy duty triple-bot interlink!"
- bot_access_flags = FLOOR_BOT|CLEAN_BOT|MED_BOT
- access_dronephone = 1
-
-/obj/item/weapon/cartridge/signal
- name = "generic signaler cartridge"
- desc = "A data cartridge with an integrated radio signaler module."
-
-/obj/item/weapon/cartridge/signal/toxins
- name = "\improper Signal Ace 2 cartridge"
- desc = "Complete with integrated radio signaler!"
- icon_state = "cart-tox"
- access_reagent_scanner = 1
- access_atmos = 1
-
-/obj/item/weapon/cartridge/signal/New()
- ..()
- radio = new /obj/item/radio/integrated/signal(src)
-
-
-
-/obj/item/weapon/cartridge/quartermaster
- name = "space parts & space vendors cartridge"
- desc = "Perfect for the Quartermaster on the go!"
- icon_state = "cart-q"
- access_quartermaster = 1
- bot_access_flags = MULE_BOT
-
-/obj/item/weapon/cartridge/head
- name = "\improper Easy-Record DELUXE cartridge"
- icon_state = "cart-h"
- access_manifest = 1
- access_status_display = 1
-
-/obj/item/weapon/cartridge/hop
- name = "\improper HumanResources9001 cartridge"
- icon_state = "cart-h"
- access_manifest = 1
- access_status_display = 1
- bot_access_flags = MULE_BOT|CLEAN_BOT
- access_janitor = 1
- access_security = 1
- access_newscaster = 1
- access_quartermaster = 1
- access_dronephone = 1
-
-/obj/item/weapon/cartridge/hos
- name = "\improper R.O.B.U.S.T. DELUXE cartridge"
- icon_state = "cart-hos"
- access_manifest = 1
- access_status_display = 1
- access_security = 1
- bot_access_flags = SEC_BOT
-
-
-/obj/item/weapon/cartridge/ce
- name = "\improper Power-On DELUXE cartridge"
- icon_state = "cart-ce"
- access_manifest = 1
- access_status_display = 1
- access_engine = 1
- access_atmos = 1
- access_dronephone = 1
- bot_access_flags = FLOOR_BOT
-
-/obj/item/weapon/cartridge/cmo
- name = "\improper Med-U DELUXE cartridge"
- icon_state = "cart-cmo"
- access_manifest = 1
- access_status_display = 1
- access_reagent_scanner = 1
- access_medical = 1
- bot_access_flags = MED_BOT
-
-/obj/item/weapon/cartridge/rd
- name = "\improper Signal Ace DELUXE cartridge"
- icon_state = "cart-rd"
- access_manifest = 1
- access_status_display = 1
- access_reagent_scanner = 1
- access_atmos = 1
- access_dronephone = 1
- bot_access_flags = FLOOR_BOT|CLEAN_BOT|MED_BOT
-
-/obj/item/weapon/cartridge/rd/New()
- ..()
- radio = new /obj/item/radio/integrated/signal(src)
-
-/obj/item/weapon/cartridge/captain
- name = "\improper Value-PAK cartridge"
- desc = "Now with 350% more value!" //Give the Captain...EVERYTHING! (Except Mime and Clown)
- icon_state = "cart-c"
- access_manifest = 1
- access_engine = 1
- access_security = 1
- access_medical = 1
- access_reagent_scanner = 1
- access_status_display = 1
- access_atmos = 1
- access_newscaster = 1
- access_quartermaster = 1
- access_janitor = 1
- access_dronephone = 1
- bot_access_flags = SEC_BOT|MULE_BOT|FLOOR_BOT|CLEAN_BOT|MED_BOT
- spam_enabled = 1
-
-/obj/item/weapon/cartridge/captain/New()
- ..()
- radio = new /obj/item/radio/integrated/signal(src)
-
-/obj/item/weapon/cartridge/syndicate
- name = "\improper Detomatix cartridge"
- icon_state = "cart"
- access_remote_door = 1
- remote_door_id = "smindicate" //Make sure this matches the syndicate shuttle's shield/door id!! //don't ask about the name, testing.
- var/shock_charges = 4
-
-/obj/item/weapon/cartridge/proc/unlock()
- if (!istype(loc, /obj/item/device/pda))
- return
-
- generate_menu()
- print_to_host(menu)
- return
-
-/obj/item/weapon/cartridge/proc/print_to_host(text)
- if (!istype(loc, /obj/item/device/pda))
- return
- var/obj/item/device/pda/P = loc
- P.cart = text
-
- for (var/mob/M in viewers(1, loc.loc))
- if (M.client && M.machine == loc)
- P.attack_self(M)
-
- return
-
-/obj/item/weapon/cartridge/proc/post_status(command, data1, data2)
-
- var/datum/radio_frequency/frequency = SSradio.return_frequency(1435)
-
- if(!frequency) return
-
- var/datum/signal/status_signal = new
- status_signal.source = src
- status_signal.transmission_method = 1
- status_signal.data["command"] = command
-
- switch(command)
- if("message")
- status_signal.data["msg1"] = data1
- status_signal.data["msg2"] = data2
- if("alert")
- status_signal.data["picture_state"] = data1
-
- frequency.post_signal(src, status_signal)
-
-
-/obj/item/weapon/cartridge/proc/generate_menu(mob/user)
- switch(mode)
- if(40) //signaller
- var/obj/item/radio/integrated/signal/S = radio
- menu = "
Remote Signaling System
"
-
- menu += {"
-Send Signal
-Frequency:
--
--
-[format_frequency(S.frequency)]
-+
-+
-
-Code:
--
--
-[S.code]
-+
-+
"}
- if (41) //crew manifest
-
- menu = "
Crew Manifest
"
- menu += "Entries cannot be modified from this terminal.
"
- if(GLOB.data_core.general)
- for (var/datum/data/record/t in sortRecord(GLOB.data_core.general))
- menu += "[t.fields["name"]] - [t.fields["rank"]]
"
- menu += "
"
-
-
- if (42) //status displays
- menu = "
Station Status Display Interlink
"
-
- menu += "\[ Clear \]
"
- menu += "\[ Shuttle ETA \]
"
- menu += "\[ Message \]"
- menu += "
"
- menu += "\[ Alert: None |"
- menu += " Red Alert |"
- menu += " Lockdown |"
- menu += " Biohazard \]
"
-
- if (43)
- menu = "
Power Monitors - Please select one
"
- powmonitor = null
- powermonitors = list()
- var/powercount = 0
-
-
-
- for(var/obj/machinery/computer/monitor/pMon in GLOB.machines)
- if(!(pMon.stat & (NOPOWER|BROKEN)) )
- powercount++
- powermonitors += pMon
-
-
- if(!powercount)
- menu += "No connection
"
- else
-
- menu += ""
- var/count = 0
- for(var/obj/machinery/computer/monitor/pMon in powermonitors)
- count++
- menu += "[pMon]
"
-
- menu += ""
-
- if (433)
- menu = "
Power Monitor
"
- if(!powmonitor)
- menu += "No connection
"
- else
- var/list/L = list()
- for(var/obj/machinery/power/terminal/term in powmonitor.attached.powernet.nodes)
- if(istype(term.master, /obj/machinery/power/apc))
- var/obj/machinery/power/apc/A = term.master
- L += A
-
- menu += "Total power: [powmonitor.attached.powernet.viewavail] W
Total load: [num2text(powmonitor.attached.powernet.viewload,10)] W
"
-
- menu += ""
-
- if(L.len > 0)
- menu += "Area Eqp./Lgt./Env. Load Cell
"
-
- var/list/S = list(" Off","AOff"," On", " AOn")
- var/list/chg = list("N","C","F")
-
- for(var/obj/machinery/power/apc/A in L)
- menu += copytext(add_tspace(A.area.name, 30), 1, 30)
- menu += " [S[A.equipment+1]] [S[A.lighting+1]] [S[A.environ+1]] [add_lspace(A.lastused_total, 6)] [A.cell ? "[add_lspace(round(A.cell.percent()), 3)]% [chg[A.charging+1]]" : " N/C"]
"
-
- menu += "
"
-
- if (44) //medical records //This thing only displays a single screen so it's hard to really get the sub-menu stuff working.
- menu = "
Medical Record List
"
- if(GLOB.data_core.general)
- for(var/datum/data/record/R in sortRecord(GLOB.data_core.general))
- menu += "[R.fields["id"]]: [R.fields["name"]]
"
- menu += "
"
- if(441)
- menu = "
Medical Record
"
-
- if(active1 in GLOB.data_core.general)
- menu += "Name: [active1.fields["name"]] ID: [active1.fields["id"]]
"
- menu += "Sex: [active1.fields["sex"]]
"
- menu += "Age: [active1.fields["age"]]
"
- menu += "Rank: [active1.fields["rank"]]
"
- menu += "Fingerprint: [active1.fields["fingerprint"]]
"
- menu += "Physical Status: [active1.fields["p_stat"]]
"
- menu += "Mental Status: [active1.fields["m_stat"]]
"
- else
- menu += "Record Lost!
"
-
- menu += "
"
-
- menu += "
Medical Data
"
- if(active2 in GLOB.data_core.medical)
- menu += "Blood Type: [active2.fields["blood_type"]]
"
-
- menu += "Minor Disabilities: [active2.fields["mi_dis"]]
"
- menu += "Details: [active2.fields["mi_dis_d"]]
"
-
- menu += "Major Disabilities: [active2.fields["ma_dis"]]
"
- menu += "Details: [active2.fields["ma_dis_d"]]
"
-
- menu += "Allergies: [active2.fields["alg"]]
"
- menu += "Details: [active2.fields["alg_d"]]
"
-
- menu += "Current Diseases: [active2.fields["cdi"]]
"
- menu += "Details: [active2.fields["cdi_d"]]
"
-
- menu += "Important Notes: [active2.fields["notes"]]
"
- else
- menu += "Record Lost!
"
-
- menu += "
"
- if (45) //security records
- menu = "
Security Record List
"
- if(GLOB.data_core.general)
- for (var/datum/data/record/R in sortRecord(GLOB.data_core.general))
- menu += "[R.fields["id"]]: [R.fields["name"]]
"
-
- menu += "
"
- if(451)
- menu = "
Security Record
"
-
- if(active1 in GLOB.data_core.general)
- menu += "Name: [active1.fields["name"]] ID: [active1.fields["id"]]
"
- menu += "Sex: [active1.fields["sex"]]
"
- menu += "Age: [active1.fields["age"]]
"
- menu += "Rank: [active1.fields["rank"]]
"
- menu += "Fingerprint: [active1.fields["fingerprint"]]
"
- menu += "Physical Status: [active1.fields["p_stat"]]
"
- menu += "Mental Status: [active1.fields["m_stat"]]
"
- else
- menu += "Record Lost!
"
-
- menu += "
"
-
- menu += "
Security Data
"
- if(active3 in GLOB.data_core.security)
- menu += "Criminal Status: [active3.fields["criminal"]]
"
-
- menu += text("
\nMinor Crimes:")
-
- menu +={"
-
-| Crime |
-Details |
-Author |
-Time Added |
-
"}
- for(var/datum/data/crime/c in active3.fields["mi_crim"])
- menu += "| [c.crimeName] | "
- menu += "[c.crimeDetails] | "
- menu += "[c.author] | "
- menu += "[c.time] | "
- menu += "
"
- menu += "
"
-
- menu += text("
\nMajor Crimes:")
-
- menu +={"
-
-| Crime |
-Details |
-Author |
-Time Added |
-
"}
- for(var/datum/data/crime/c in active3.fields["ma_crim"])
- menu += "| [c.crimeName] | "
- menu += "[c.crimeDetails] | "
- menu += "[c.author] | "
- menu += "[c.time] | "
- menu += "
"
- menu += "
"
-
- menu += "
\nImportant Notes:
"
- menu += "[active3.fields["notes"]]"
- else
- menu += "Record Lost!
"
-
- menu += "
"
-
- if (47) //quartermaster order records
- menu = "
Supply Record Interlink
"
-
- menu += "
Supply shuttle
"
- menu += "Location: "
- switch(SSshuttle.supply.mode)
- if(SHUTTLE_CALL)
- menu += "Moving to "
- if(SSshuttle.supply.z != ZLEVEL_STATION)
- menu += "station"
- else
- menu += "centcomm"
- menu += " ([SSshuttle.supply.timeLeft(600)] Mins)"
- else
- menu += "At "
- if(SSshuttle.supply.z != ZLEVEL_STATION)
- menu += "centcomm"
- else
- menu += "station"
- menu += "
Current approved orders:
"
- for(var/S in SSshuttle.shoppinglist)
- var/datum/supply_order/SO = S
- menu += "- #[SO.id] - [SO.pack.name] approved by [SO.orderer] [SO.reason ? "([SO.reason])":""]
"
- menu += "
"
-
- menu += "Current requests:
"
- for(var/S in SSshuttle.requestlist)
- var/datum/supply_order/SO = S
- menu += "- #[SO.id] - [SO.pack.name] requested by [SO.orderer]
"
- menu += "
Upgrade NOW to Space Parts & Space Vendors PLUS for full remote order control and inventory management."
-
- if (49) //janitorial locator
- menu = "
Persistent Custodial Object Locator
"
-
- var/turf/cl = get_turf(src)
- if (cl)
- menu += "Current Orbital Location: \[[cl.x],[cl.y]\]"
-
- menu += "Located Mops:
"
-
- var/ldat
- for (var/obj/item/weapon/mop/M in world)
- var/turf/ml = get_turf(M)
-
- if(ml)
- if (ml.z != cl.z)
- continue
- var/direction = get_dir(src, M)
- ldat += "Mop - \[[ml.x],[ml.y] ([uppertext(dir2text(direction))])\] - [M.reagents.total_volume ? "Wet" : "Dry"]
"
-
- if (!ldat)
- menu += "None"
- else
- menu += "[ldat]"
-
- menu += "Located Janitorial Cart:
"
-
- ldat = null
- for (var/obj/structure/janitorialcart/B in world)
- var/turf/bl = get_turf(B)
-
- if(bl)
- if (bl.z != cl.z)
- continue
- var/direction = get_dir(src, B)
- ldat += "Cart - \[[bl.x],[bl.y] ([uppertext(dir2text(direction))])\] - Water level: [B.reagents.total_volume]/100
"
-
- if (!ldat)
- menu += "None"
- else
- menu += "[ldat]"
-
- menu += "Located Cleanbots:
"
-
- ldat = null
- for (var/mob/living/simple_animal/bot/cleanbot/B in GLOB.living_mob_list)
- var/turf/bl = get_turf(B)
-
- if(bl)
- if (bl.z != cl.z)
- continue
- var/direction = get_dir(src, B)
- ldat += "Cleanbot - \[[bl.x],[bl.y] ([uppertext(dir2text(direction))])\] - [B.on ? "Online" : "Offline"]
"
-
- if (!ldat)
- menu += "None"
- else
- menu += "[ldat]"
-
- else
- menu += "ERROR: Unable to determine current location."
- menu += "
Refresh GPS Locator"
-
- if (53) // Newscaster
- menu = "
Newscaster Access
"
- menu += "
Current Newsfeed: [current_channel ? current_channel : "None"]
"
- var/datum/newscaster/feed_channel/current
- for(var/datum/newscaster/feed_channel/chan in GLOB.news_network.network_channels)
- if (chan.channel_name == current_channel)
- current = chan
- if(!current)
- menu += " ERROR : NO CHANNEL FOUND
"
- return
- var/i = 1
- for(var/datum/newscaster/feed_message/msg in current.messages)
- menu +="-[msg.returnBody(-1)]
\[Story by [msg.returnAuthor(-1)]\]
"
- menu +="[msg.comments.len] comment[msg.comments.len > 1 ? "s" : ""]
"
- if(msg.img)
- user << browse_rsc(msg.img, "tmp_photo[i].png")
- menu +="
"
- i++
- for(var/datum/newscaster/feed_comment/comment in msg.comments)
- menu +="[comment.body]
[comment.author] [comment.time_stamp]
"
- menu += "
Post Message"
-
- if (54) // Beepsky, Medibot, Floorbot, and Cleanbot access
- menu = "
Bots Interlink
"
- bot_control()
-
-/obj/item/weapon/cartridge/Topic(href, href_list)
- ..()
-
- if (!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr))
- usr.unset_machine()
- usr << browse(null, "window=pda")
- return
-
- var/obj/item/device/pda/pda = loc
-
- switch(href_list["choice"])
- if("Medical Records")
- active1 = find_record("id", href_list["target"], GLOB.data_core.general)
- if(active1)
- active2 = find_record("id", href_list["target"], GLOB.data_core.medical)
- pda.mode = 441
- mode = 441
- if(!active2)
- active1 = null
-
- if("Security Records")
- active1 = find_record("id", href_list["target"], GLOB.data_core.general)
- if(active1)
- active3 = find_record("id", href_list["target"], GLOB.data_core.security)
- pda.mode = 451
- mode = 451
- if(!active3)
- active1 = null
-
- if("Send Signal")
- spawn( 0 )
- var/obj/item/radio/integrated/signal/S = radio
- S.send_signal("ACTIVATE")
- return
-
- if("Signal Frequency")
- var/obj/item/radio/integrated/signal/S = radio
- var/new_frequency = sanitize_frequency(S.frequency + text2num(href_list["sfreq"]))
- S.set_frequency(new_frequency)
-
- if("Signal Code")
- var/obj/item/radio/integrated/signal/S = radio
- S.code += text2num(href_list["scode"])
- S.code = round(S.code)
- S.code = min(100, S.code)
- S.code = max(1, S.code)
-
- if("Status")
- switch(href_list["statdisp"])
- if("message")
- post_status("message", message1, message2)
- if("alert")
- post_status("alert", href_list["alert"])
- if("setmsg1")
- message1 = reject_bad_text(input("Line 1", "Enter Message Text", message1) as text|null, 40)
- updateSelfDialog()
- if("setmsg2")
- message2 = reject_bad_text(input("Line 2", "Enter Message Text", message2) as text|null, 40)
- updateSelfDialog()
- else
- post_status(href_list["statdisp"])
- if("Power Select")
- var/pnum = text2num(href_list["target"])
- powmonitor = powermonitors[pnum]
- pda.mode = 433
- mode = 433
-
- if("Supply Orders")
- pda.mode =47
- mode = 47
-
- if("Newscaster Access")
- mode = 53
-
- if("Newscaster Message")
- var/pda_owner_name = pda.id ? "[pda.id.registered_name] ([pda.id.assignment])" : "Unknown"
- var/message = pda.msg_input()
- var/datum/newscaster/feed_channel/current
- for(var/datum/newscaster/feed_channel/chan in GLOB.news_network.network_channels)
- if (chan.channel_name == current_channel)
- current = chan
- if(current.locked && current.author != pda_owner_name)
- pda.cart += " ERROR : NOT AUTHORIZED [pda.id ? "" : "- ID SLOT EMPTY"]
"
- pda.Topic(null,list("choice"="Refresh"))
- return
- GLOB.news_network.SubmitArticle(message,pda.owner,current_channel)
- pda.Topic(null,list("choice"=num2text(mode)))
- return
-
- if("Newscaster Switch Channel")
- current_channel = pda.msg_input()
- pda.Topic(null,list("choice"=num2text(mode)))
- return
-
- //Bot control section! Viciously ripped from radios for being laggy and terrible.
- if(href_list["op"])
- switch(href_list["op"])
-
- if("control")
- active_bot = locate(href_list["bot"])
-
- if("botlist")
- active_bot = null
- if("summon") //Args are in the correct order, they are stated here just as an easy reminder.
- active_bot.bot_control(command= "summon", user_turf= get_turf(usr), user_access= pda.GetAccess())
- else //Forward all other bot commands to the bot itself!
- active_bot.bot_control(command= href_list["op"], user= usr)
-
- if(href_list["mule"]) //MULEbots are special snowflakes, and need different args due to how they work.
-
- active_bot.bot_control(command= href_list["mule"], user= usr, pda= 1)
-
- generate_menu(usr)
- print_to_host(menu)
-
-
-
-/obj/item/weapon/cartridge/proc/bot_control()
-
-
- var/mob/living/simple_animal/bot/Bot
-
-// if(!SC)
-// menu = "Interlink Error - Please reinsert cartridge."
-// return
- if(active_bot)
- menu += "[active_bot]
Status: (
refresh)
"
- menu += "Model: [active_bot.model]
"
- menu += "Location: [get_area(active_bot)]
"
- menu += "Mode: [active_bot.get_mode()]"
- if(active_bot.allow_pai)
- menu += "
pAI: "
- if(active_bot.paicard && active_bot.paicard.pai)
- menu += "[active_bot.paicard.pai.name]"
- if(active_bot.bot_core.allowed(usr))
- menu += " (eject)"
- else
- menu += "none"
-
- //MULEs!
- if(active_bot.bot_type == MULE_BOT)
- var/mob/living/simple_animal/bot/mulebot/MULE = active_bot
- var/atom/Load = MULE.load
- menu += "
Current Load: [ !Load ? "none" : "[Load.name] (unload)" ]
"
- menu += "Destination: [MULE.destination ? MULE.destination : "None"] (set)
"
- menu += "Set ID: [MULE.suffix] Modify
"
- menu += "Power: [MULE.cell ? MULE.cell.percent() : 0]%
"
- menu += "Home: [!MULE.home_destination ? "none" : MULE.home_destination ]
"
- menu += "Delivery Reporting: [MULE.report_delivery ? "(On)": "(Off)"]
"
- menu += "Auto Return Home: [MULE.auto_return ? "(On)": "(Off)"]
"
- menu += "Auto Pickup Crate: [MULE.auto_pickup ? "(On)": "(Off)"]
" //Hue.
-
- menu += "\[Stop\] "
- menu += "\[Proceed\] "
- menu += "\[Return Home\]
"
-
- else
- menu += "
\[Stop Patrol\] " //patrolon
- menu += "\[Start Patrol\] " //patroloff
- menu += "\[Summon Bot\]
" //summon
- menu += "Keep an ID inserted to upload access codes upon summoning."
-
- menu += "
Return to bot list"
- else
- menu += "
Scan for active bots
"
- var/turf/current_turf = get_turf(src)
- var/zlevel = current_turf.z
- var/botcount = 0
- for(Bot in GLOB.living_mob_list) //Git da botz
- if(!Bot.on || Bot.z != zlevel || Bot.remote_disabled || !(bot_access_flags & Bot.bot_type)) //Only non-emagged bots on the same Z-level are detected!
- continue //Also, the PDA must have access to the bot type.
- menu += "[Bot.name] ([Bot.get_mode()])
"
- botcount++
- if(!botcount) //No bots at all? Lame.
- menu += "No bots found.
"
- return
-
- return menu
+/obj/item/weapon/cartridge
+ name = "generic cartridge"
+ desc = "A data cartridge for portable microcomputers."
+ icon = 'icons/obj/pda.dmi'
+ icon_state = "cart"
+ item_state = "electronic"
+ w_class = WEIGHT_CLASS_TINY
+
+ var/obj/item/radio/integrated/radio = null
+ var/access_security = 0
+ var/access_engine = 0
+ var/access_atmos = 0
+ var/access_medical = 0
+ var/access_manifest = 0
+ var/access_clown = 0
+ var/access_mime = 0
+ var/access_janitor = 0
+// var/access_flora = 0
+ var/access_reagent_scanner = 0
+ var/access_newscaster = 0
+ var/access_remote_door = 0 //Control some blast doors remotely!!
+ var/remote_door_id = ""
+ var/access_status_display = 0
+ var/access_quartermaster = 0
+ var/access_hydroponics = 0
+ var/access_dronephone = 0
+ var/bot_access_flags = 0 //Bit flags. Selection: SEC_BOT|MULE_BOT|FLOOR_BOT|CLEAN_BOT|MED_BOT
+ var/spam_enabled = 0 //Enables "Send to All" Option
+
+ var/mode = null
+ var/menu
+ var/datum/data/record/active1 = null //General
+ var/datum/data/record/active2 = null //Medical
+ var/datum/data/record/active3 = null //Security
+ var/obj/machinery/computer/monitor/powmonitor = null // Power Monitor
+ var/list/powermonitors = list()
+ var/message1 // used for status_displays
+ var/message2
+ var/list/stored_data = list()
+ var/current_channel
+
+ var/mob/living/simple_animal/bot/active_bot
+ var/list/botlist = list()
+
+/obj/item/weapon/cartridge/engineering
+ name = "\improper Power-ON cartridge"
+ icon_state = "cart-e"
+ access_engine = 1
+ access_dronephone = 1
+ bot_access_flags = FLOOR_BOT
+
+/obj/item/weapon/cartridge/atmos
+ name = "\improper BreatheDeep cartridge"
+ icon_state = "cart-a"
+ access_atmos = 1
+ access_dronephone = 1
+ bot_access_flags = FLOOR_BOT
+
+/obj/item/weapon/cartridge/medical
+ name = "\improper Med-U cartridge"
+ icon_state = "cart-m"
+ access_medical = 1
+ bot_access_flags = MED_BOT
+
+/obj/item/weapon/cartridge/chemistry
+ name = "\improper ChemWhiz cartridge"
+ icon_state = "cart-chem"
+ access_reagent_scanner = 1
+ bot_access_flags = MED_BOT
+
+/obj/item/weapon/cartridge/security
+ name = "\improper R.O.B.U.S.T. cartridge"
+ icon_state = "cart-s"
+ access_security = 1
+ bot_access_flags = SEC_BOT
+
+/obj/item/weapon/cartridge/detective
+ name = "\improper D.E.T.E.C.T. cartridge"
+ icon_state = "cart-s"
+ access_security = 1
+ access_medical = 1
+ access_manifest = 1
+ bot_access_flags = SEC_BOT
+
+/obj/item/weapon/cartridge/janitor
+ name = "\improper CustodiPRO cartridge"
+ desc = "The ultimate in clean-room design."
+ icon_state = "cart-j"
+ access_janitor = 1
+ access_dronephone = 1
+ bot_access_flags = CLEAN_BOT
+
+/obj/item/weapon/cartridge/lawyer
+ name = "\improper P.R.O.V.E. cartridge"
+ icon_state = "cart-s"
+ access_security = 1
+ spam_enabled = 1
+
+/obj/item/weapon/cartridge/clown
+ name = "\improper Honkworks 5.0 cartridge"
+ icon_state = "cart-clown"
+ access_clown = 1
+ var/honk_charges = 5
+
+/obj/item/weapon/cartridge/mime
+ name = "\improper Gestur-O 1000 cartridge"
+ icon_state = "cart-mi"
+ access_mime = 1
+ var/mime_charges = 5
+
+/obj/item/weapon/cartridge/curator
+ name = "\improper Lib-Tweet cartridge"
+ icon_state = "cart-s"
+ access_newscaster = 1
+
+/*
+/obj/item/weapon/cartridge/botanist
+ name = "\improper Green Thumb v4.20 cartridge"
+ icon_state = "cart-b"
+ access_flora = 1
+*/
+
+/obj/item/weapon/cartridge/roboticist
+ name = "\improper B.O.O.P. Remote Control cartridge"
+ desc = "Packed with heavy duty triple-bot interlink!"
+ bot_access_flags = FLOOR_BOT|CLEAN_BOT|MED_BOT
+ access_dronephone = 1
+
+/obj/item/weapon/cartridge/signal
+ name = "generic signaler cartridge"
+ desc = "A data cartridge with an integrated radio signaler module."
+
+/obj/item/weapon/cartridge/signal/toxins
+ name = "\improper Signal Ace 2 cartridge"
+ desc = "Complete with integrated radio signaler!"
+ icon_state = "cart-tox"
+ access_reagent_scanner = 1
+ access_atmos = 1
+
+/obj/item/weapon/cartridge/signal/New()
+ ..()
+ radio = new /obj/item/radio/integrated/signal(src)
+
+
+
+/obj/item/weapon/cartridge/quartermaster
+ name = "space parts & space vendors cartridge"
+ desc = "Perfect for the Quartermaster on the go!"
+ icon_state = "cart-q"
+ access_quartermaster = 1
+ bot_access_flags = MULE_BOT
+
+/obj/item/weapon/cartridge/head
+ name = "\improper Easy-Record DELUXE cartridge"
+ icon_state = "cart-h"
+ access_manifest = 1
+ access_status_display = 1
+
+/obj/item/weapon/cartridge/hop
+ name = "\improper HumanResources9001 cartridge"
+ icon_state = "cart-h"
+ access_manifest = 1
+ access_status_display = 1
+ bot_access_flags = MULE_BOT|CLEAN_BOT
+ access_janitor = 1
+ access_security = 1
+ access_newscaster = 1
+ access_quartermaster = 1
+ access_dronephone = 1
+
+/obj/item/weapon/cartridge/hos
+ name = "\improper R.O.B.U.S.T. DELUXE cartridge"
+ icon_state = "cart-hos"
+ access_manifest = 1
+ access_status_display = 1
+ access_security = 1
+ bot_access_flags = SEC_BOT
+
+
+/obj/item/weapon/cartridge/ce
+ name = "\improper Power-On DELUXE cartridge"
+ icon_state = "cart-ce"
+ access_manifest = 1
+ access_status_display = 1
+ access_engine = 1
+ access_atmos = 1
+ access_dronephone = 1
+ bot_access_flags = FLOOR_BOT
+
+/obj/item/weapon/cartridge/cmo
+ name = "\improper Med-U DELUXE cartridge"
+ icon_state = "cart-cmo"
+ access_manifest = 1
+ access_status_display = 1
+ access_reagent_scanner = 1
+ access_medical = 1
+ bot_access_flags = MED_BOT
+
+/obj/item/weapon/cartridge/rd
+ name = "\improper Signal Ace DELUXE cartridge"
+ icon_state = "cart-rd"
+ access_manifest = 1
+ access_status_display = 1
+ access_reagent_scanner = 1
+ access_atmos = 1
+ access_dronephone = 1
+ bot_access_flags = FLOOR_BOT|CLEAN_BOT|MED_BOT
+
+/obj/item/weapon/cartridge/rd/New()
+ ..()
+ radio = new /obj/item/radio/integrated/signal(src)
+
+/obj/item/weapon/cartridge/captain
+ name = "\improper Value-PAK cartridge"
+ desc = "Now with 350% more value!" //Give the Captain...EVERYTHING! (Except Mime and Clown)
+ icon_state = "cart-c"
+ access_manifest = 1
+ access_engine = 1
+ access_security = 1
+ access_medical = 1
+ access_reagent_scanner = 1
+ access_status_display = 1
+ access_atmos = 1
+ access_newscaster = 1
+ access_quartermaster = 1
+ access_janitor = 1
+ access_dronephone = 1
+ bot_access_flags = SEC_BOT|MULE_BOT|FLOOR_BOT|CLEAN_BOT|MED_BOT
+ spam_enabled = 1
+
+/obj/item/weapon/cartridge/captain/New()
+ ..()
+ radio = new /obj/item/radio/integrated/signal(src)
+
+/obj/item/weapon/cartridge/syndicate
+ name = "\improper Detomatix cartridge"
+ icon_state = "cart"
+ access_remote_door = 1
+ remote_door_id = "smindicate" //Make sure this matches the syndicate shuttle's shield/door id!! //don't ask about the name, testing.
+ var/shock_charges = 4
+
+/obj/item/weapon/cartridge/proc/unlock()
+ if (!istype(loc, /obj/item/device/pda))
+ return
+
+ generate_menu()
+ print_to_host(menu)
+ return
+
+/obj/item/weapon/cartridge/proc/print_to_host(text)
+ if (!istype(loc, /obj/item/device/pda))
+ return
+ var/obj/item/device/pda/P = loc
+ P.cart = text
+
+ for (var/mob/M in viewers(1, loc.loc))
+ if (M.client && M.machine == loc)
+ P.attack_self(M)
+
+ return
+
+/obj/item/weapon/cartridge/proc/post_status(command, data1, data2)
+
+ var/datum/radio_frequency/frequency = SSradio.return_frequency(1435)
+
+ if(!frequency) return
+
+ var/datum/signal/status_signal = new
+ status_signal.source = src
+ status_signal.transmission_method = 1
+ status_signal.data["command"] = command
+
+ switch(command)
+ if("message")
+ status_signal.data["msg1"] = data1
+ status_signal.data["msg2"] = data2
+ if("alert")
+ status_signal.data["picture_state"] = data1
+
+ frequency.post_signal(src, status_signal)
+
+
+/obj/item/weapon/cartridge/proc/generate_menu(mob/user)
+ switch(mode)
+ if(40) //signaller
+ var/obj/item/radio/integrated/signal/S = radio
+ menu = "
Remote Signaling System
"
+
+ menu += {"
+Send Signal
+Frequency:
+-
+-
+[format_frequency(S.frequency)]
++
++
+
+Code:
+-
+-
+[S.code]
++
++
"}
+ if (41) //crew manifest
+
+ menu = "
Crew Manifest
"
+ menu += "Entries cannot be modified from this terminal.
"
+ if(GLOB.data_core.general)
+ for (var/datum/data/record/t in sortRecord(GLOB.data_core.general))
+ menu += "[t.fields["name"]] - [t.fields["rank"]]
"
+ menu += "
"
+
+
+ if (42) //status displays
+ menu = "
Station Status Display Interlink
"
+
+ menu += "\[ Clear \]
"
+ menu += "\[ Shuttle ETA \]
"
+ menu += "\[ Message \]"
+ menu += "
"
+ menu += "\[ Alert: None |"
+ menu += " Red Alert |"
+ menu += " Lockdown |"
+ menu += " Biohazard \]
"
+
+ if (43)
+ menu = "
Power Monitors - Please select one
"
+ powmonitor = null
+ powermonitors = list()
+ var/powercount = 0
+
+
+
+ for(var/obj/machinery/computer/monitor/pMon in GLOB.machines)
+ if(!(pMon.stat & (NOPOWER|BROKEN)) )
+ powercount++
+ powermonitors += pMon
+
+
+ if(!powercount)
+ menu += "No connection
"
+ else
+
+ menu += ""
+ var/count = 0
+ for(var/obj/machinery/computer/monitor/pMon in powermonitors)
+ count++
+ menu += "[pMon]
"
+
+ menu += ""
+
+ if (433)
+ menu = "
Power Monitor
"
+ if(!powmonitor)
+ menu += "No connection
"
+ else
+ var/list/L = list()
+ for(var/obj/machinery/power/terminal/term in powmonitor.attached.powernet.nodes)
+ if(istype(term.master, /obj/machinery/power/apc))
+ var/obj/machinery/power/apc/A = term.master
+ L += A
+
+ menu += "Total power: [powmonitor.attached.powernet.viewavail] W
Total load: [num2text(powmonitor.attached.powernet.viewload,10)] W
"
+
+ menu += ""
+
+ if(L.len > 0)
+ menu += "Area Eqp./Lgt./Env. Load Cell
"
+
+ var/list/S = list(" Off","AOff"," On", " AOn")
+ var/list/chg = list("N","C","F")
+
+ for(var/obj/machinery/power/apc/A in L)
+ menu += copytext(add_tspace(A.area.name, 30), 1, 30)
+ menu += " [S[A.equipment+1]] [S[A.lighting+1]] [S[A.environ+1]] [add_lspace(A.lastused_total, 6)] [A.cell ? "[add_lspace(round(A.cell.percent()), 3)]% [chg[A.charging+1]]" : " N/C"]
"
+
+ menu += "
"
+
+ if (44) //medical records //This thing only displays a single screen so it's hard to really get the sub-menu stuff working.
+ menu = "
Medical Record List
"
+ if(GLOB.data_core.general)
+ for(var/datum/data/record/R in sortRecord(GLOB.data_core.general))
+ menu += "[R.fields["id"]]: [R.fields["name"]]
"
+ menu += "
"
+ if(441)
+ menu = "
Medical Record
"
+
+ if(active1 in GLOB.data_core.general)
+ menu += "Name: [active1.fields["name"]] ID: [active1.fields["id"]]
"
+ menu += "Sex: [active1.fields["sex"]]
"
+ menu += "Age: [active1.fields["age"]]
"
+ menu += "Rank: [active1.fields["rank"]]
"
+ menu += "Fingerprint: [active1.fields["fingerprint"]]
"
+ menu += "Physical Status: [active1.fields["p_stat"]]
"
+ menu += "Mental Status: [active1.fields["m_stat"]]
"
+ else
+ menu += "Record Lost!
"
+
+ menu += "
"
+
+ menu += "
Medical Data
"
+ if(active2 in GLOB.data_core.medical)
+ menu += "Blood Type: [active2.fields["blood_type"]]
"
+
+ menu += "Minor Disabilities: [active2.fields["mi_dis"]]
"
+ menu += "Details: [active2.fields["mi_dis_d"]]
"
+
+ menu += "Major Disabilities: [active2.fields["ma_dis"]]
"
+ menu += "Details: [active2.fields["ma_dis_d"]]
"
+
+ menu += "Allergies: [active2.fields["alg"]]
"
+ menu += "Details: [active2.fields["alg_d"]]
"
+
+ menu += "Current Diseases: [active2.fields["cdi"]]
"
+ menu += "Details: [active2.fields["cdi_d"]]
"
+
+ menu += "Important Notes: [active2.fields["notes"]]
"
+ else
+ menu += "Record Lost!
"
+
+ menu += "
"
+ if (45) //security records
+ menu = "
Security Record List
"
+ if(GLOB.data_core.general)
+ for (var/datum/data/record/R in sortRecord(GLOB.data_core.general))
+ menu += "[R.fields["id"]]: [R.fields["name"]]
"
+
+ menu += "
"
+ if(451)
+ menu = "
Security Record
"
+
+ if(active1 in GLOB.data_core.general)
+ menu += "Name: [active1.fields["name"]] ID: [active1.fields["id"]]
"
+ menu += "Sex: [active1.fields["sex"]]
"
+ menu += "Age: [active1.fields["age"]]
"
+ menu += "Rank: [active1.fields["rank"]]
"
+ menu += "Fingerprint: [active1.fields["fingerprint"]]
"
+ menu += "Physical Status: [active1.fields["p_stat"]]
"
+ menu += "Mental Status: [active1.fields["m_stat"]]
"
+ else
+ menu += "Record Lost!
"
+
+ menu += "
"
+
+ menu += "
Security Data
"
+ if(active3 in GLOB.data_core.security)
+ menu += "Criminal Status: [active3.fields["criminal"]]
"
+
+ menu += text("
\nMinor Crimes:")
+
+ menu +={"
+
+| Crime |
+Details |
+Author |
+Time Added |
+
"}
+ for(var/datum/data/crime/c in active3.fields["mi_crim"])
+ menu += "| [c.crimeName] | "
+ menu += "[c.crimeDetails] | "
+ menu += "[c.author] | "
+ menu += "[c.time] | "
+ menu += "
"
+ menu += "
"
+
+ menu += text("
\nMajor Crimes:")
+
+ menu +={"
+
+| Crime |
+Details |
+Author |
+Time Added |
+
"}
+ for(var/datum/data/crime/c in active3.fields["ma_crim"])
+ menu += "| [c.crimeName] | "
+ menu += "[c.crimeDetails] | "
+ menu += "[c.author] | "
+ menu += "[c.time] | "
+ menu += "
"
+ menu += "
"
+
+ menu += "
\nImportant Notes:
"
+ menu += "[active3.fields["notes"]]"
+ else
+ menu += "Record Lost!
"
+
+ menu += "
"
+
+ if (47) //quartermaster order records
+ menu = "
Supply Record Interlink
"
+
+ menu += "
Supply shuttle
"
+ menu += "Location: "
+ switch(SSshuttle.supply.mode)
+ if(SHUTTLE_CALL)
+ menu += "Moving to "
+ if(SSshuttle.supply.z != ZLEVEL_STATION)
+ menu += "station"
+ else
+ menu += "centcomm"
+ menu += " ([SSshuttle.supply.timeLeft(600)] Mins)"
+ else
+ menu += "At "
+ if(SSshuttle.supply.z != ZLEVEL_STATION)
+ menu += "centcomm"
+ else
+ menu += "station"
+ menu += "
Current approved orders:
"
+ for(var/S in SSshuttle.shoppinglist)
+ var/datum/supply_order/SO = S
+ menu += "- #[SO.id] - [SO.pack.name] approved by [SO.orderer] [SO.reason ? "([SO.reason])":""]
"
+ menu += "
"
+
+ menu += "Current requests:
"
+ for(var/S in SSshuttle.requestlist)
+ var/datum/supply_order/SO = S
+ menu += "- #[SO.id] - [SO.pack.name] requested by [SO.orderer]
"
+ menu += "
Upgrade NOW to Space Parts & Space Vendors PLUS for full remote order control and inventory management."
+
+ if (49) //janitorial locator
+ menu = "
Persistent Custodial Object Locator
"
+
+ var/turf/cl = get_turf(src)
+ if (cl)
+ menu += "Current Orbital Location: \[[cl.x],[cl.y]\]"
+
+ menu += "Located Mops:
"
+
+ var/ldat
+ for (var/obj/item/weapon/mop/M in world)
+ var/turf/ml = get_turf(M)
+
+ if(ml)
+ if (ml.z != cl.z)
+ continue
+ var/direction = get_dir(src, M)
+ ldat += "Mop - \[[ml.x],[ml.y] ([uppertext(dir2text(direction))])\] - [M.reagents.total_volume ? "Wet" : "Dry"]
"
+
+ if (!ldat)
+ menu += "None"
+ else
+ menu += "[ldat]"
+
+ menu += "Located Janitorial Cart:
"
+
+ ldat = null
+ for (var/obj/structure/janitorialcart/B in world)
+ var/turf/bl = get_turf(B)
+
+ if(bl)
+ if (bl.z != cl.z)
+ continue
+ var/direction = get_dir(src, B)
+ ldat += "Cart - \[[bl.x],[bl.y] ([uppertext(dir2text(direction))])\] - Water level: [B.reagents.total_volume]/100
"
+
+ if (!ldat)
+ menu += "None"
+ else
+ menu += "[ldat]"
+
+ menu += "Located Cleanbots:
"
+
+ ldat = null
+ for (var/mob/living/simple_animal/bot/cleanbot/B in GLOB.living_mob_list)
+ var/turf/bl = get_turf(B)
+
+ if(bl)
+ if (bl.z != cl.z)
+ continue
+ var/direction = get_dir(src, B)
+ ldat += "Cleanbot - \[[bl.x],[bl.y] ([uppertext(dir2text(direction))])\] - [B.on ? "Online" : "Offline"]
"
+
+ if (!ldat)
+ menu += "None"
+ else
+ menu += "[ldat]"
+
+ else
+ menu += "ERROR: Unable to determine current location."
+ menu += "
Refresh GPS Locator"
+
+ if (53) // Newscaster
+ menu = "
Newscaster Access
"
+ menu += "
Current Newsfeed: [current_channel ? current_channel : "None"]
"
+ var/datum/newscaster/feed_channel/current
+ for(var/datum/newscaster/feed_channel/chan in GLOB.news_network.network_channels)
+ if (chan.channel_name == current_channel)
+ current = chan
+ if(!current)
+ menu += " ERROR : NO CHANNEL FOUND
"
+ return
+ var/i = 1
+ for(var/datum/newscaster/feed_message/msg in current.messages)
+ menu +="-[msg.returnBody(-1)]
\[Story by [msg.returnAuthor(-1)]\]
"
+ menu +="[msg.comments.len] comment[msg.comments.len > 1 ? "s" : ""]
"
+ if(msg.img)
+ user << browse_rsc(msg.img, "tmp_photo[i].png")
+ menu +="
"
+ i++
+ for(var/datum/newscaster/feed_comment/comment in msg.comments)
+ menu +="[comment.body]
[comment.author] [comment.time_stamp]
"
+ menu += "
Post Message"
+
+ if (54) // Beepsky, Medibot, Floorbot, and Cleanbot access
+ menu = "
Bots Interlink
"
+ bot_control()
+
+/obj/item/weapon/cartridge/Topic(href, href_list)
+ ..()
+
+ if (!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr))
+ usr.unset_machine()
+ usr << browse(null, "window=pda")
+ return
+
+ var/obj/item/device/pda/pda = loc
+
+ switch(href_list["choice"])
+ if("Medical Records")
+ active1 = find_record("id", href_list["target"], GLOB.data_core.general)
+ if(active1)
+ active2 = find_record("id", href_list["target"], GLOB.data_core.medical)
+ pda.mode = 441
+ mode = 441
+ if(!active2)
+ active1 = null
+
+ if("Security Records")
+ active1 = find_record("id", href_list["target"], GLOB.data_core.general)
+ if(active1)
+ active3 = find_record("id", href_list["target"], GLOB.data_core.security)
+ pda.mode = 451
+ mode = 451
+ if(!active3)
+ active1 = null
+
+ if("Send Signal")
+ spawn( 0 )
+ var/obj/item/radio/integrated/signal/S = radio
+ S.send_signal("ACTIVATE")
+ return
+
+ if("Signal Frequency")
+ var/obj/item/radio/integrated/signal/S = radio
+ var/new_frequency = sanitize_frequency(S.frequency + text2num(href_list["sfreq"]))
+ S.set_frequency(new_frequency)
+
+ if("Signal Code")
+ var/obj/item/radio/integrated/signal/S = radio
+ S.code += text2num(href_list["scode"])
+ S.code = round(S.code)
+ S.code = min(100, S.code)
+ S.code = max(1, S.code)
+
+ if("Status")
+ switch(href_list["statdisp"])
+ if("message")
+ post_status("message", message1, message2)
+ if("alert")
+ post_status("alert", href_list["alert"])
+ if("setmsg1")
+ message1 = reject_bad_text(input("Line 1", "Enter Message Text", message1) as text|null, 40)
+ updateSelfDialog()
+ if("setmsg2")
+ message2 = reject_bad_text(input("Line 2", "Enter Message Text", message2) as text|null, 40)
+ updateSelfDialog()
+ else
+ post_status(href_list["statdisp"])
+ if("Power Select")
+ var/pnum = text2num(href_list["target"])
+ powmonitor = powermonitors[pnum]
+ pda.mode = 433
+ mode = 433
+
+ if("Supply Orders")
+ pda.mode =47
+ mode = 47
+
+ if("Newscaster Access")
+ mode = 53
+
+ if("Newscaster Message")
+ var/pda_owner_name = pda.id ? "[pda.id.registered_name] ([pda.id.assignment])" : "Unknown"
+ var/message = pda.msg_input()
+ var/datum/newscaster/feed_channel/current
+ for(var/datum/newscaster/feed_channel/chan in GLOB.news_network.network_channels)
+ if (chan.channel_name == current_channel)
+ current = chan
+ if(current.locked && current.author != pda_owner_name)
+ pda.cart += " ERROR : NOT AUTHORIZED [pda.id ? "" : "- ID SLOT EMPTY"]
"
+ pda.Topic(null,list("choice"="Refresh"))
+ return
+ GLOB.news_network.SubmitArticle(message,pda.owner,current_channel)
+ pda.Topic(null,list("choice"=num2text(mode)))
+ return
+
+ if("Newscaster Switch Channel")
+ current_channel = pda.msg_input()
+ pda.Topic(null,list("choice"=num2text(mode)))
+ return
+
+ //Bot control section! Viciously ripped from radios for being laggy and terrible.
+ if(href_list["op"])
+ switch(href_list["op"])
+
+ if("control")
+ active_bot = locate(href_list["bot"])
+
+ if("botlist")
+ active_bot = null
+ if("summon") //Args are in the correct order, they are stated here just as an easy reminder.
+ active_bot.bot_control(command= "summon", user_turf= get_turf(usr), user_access= pda.GetAccess())
+ else //Forward all other bot commands to the bot itself!
+ active_bot.bot_control(command= href_list["op"], user= usr)
+
+ if(href_list["mule"]) //MULEbots are special snowflakes, and need different args due to how they work.
+
+ active_bot.bot_control(command= href_list["mule"], user= usr, pda= 1)
+
+ generate_menu(usr)
+ print_to_host(menu)
+
+
+
+/obj/item/weapon/cartridge/proc/bot_control()
+
+
+ var/mob/living/simple_animal/bot/Bot
+
+// if(!SC)
+// menu = "Interlink Error - Please reinsert cartridge."
+// return
+ if(active_bot)
+ menu += "[active_bot]
Status: (
refresh)
"
+ menu += "Model: [active_bot.model]
"
+ menu += "Location: [get_area(active_bot)]
"
+ menu += "Mode: [active_bot.get_mode()]"
+ if(active_bot.allow_pai)
+ menu += "
pAI: "
+ if(active_bot.paicard && active_bot.paicard.pai)
+ menu += "[active_bot.paicard.pai.name]"
+ if(active_bot.bot_core.allowed(usr))
+ menu += " (eject)"
+ else
+ menu += "none"
+
+ //MULEs!
+ if(active_bot.bot_type == MULE_BOT)
+ var/mob/living/simple_animal/bot/mulebot/MULE = active_bot
+ var/atom/Load = MULE.load
+ menu += "
Current Load: [ !Load ? "none" : "[Load.name] (unload)" ]
"
+ menu += "Destination: [MULE.destination ? MULE.destination : "None"] (set)
"
+ menu += "Set ID: [MULE.suffix] Modify
"
+ menu += "Power: [MULE.cell ? MULE.cell.percent() : 0]%
"
+ menu += "Home: [!MULE.home_destination ? "none" : MULE.home_destination ]
"
+ menu += "Delivery Reporting: [MULE.report_delivery ? "(On)": "(Off)"]
"
+ menu += "Auto Return Home: [MULE.auto_return ? "(On)": "(Off)"]
"
+ menu += "Auto Pickup Crate: [MULE.auto_pickup ? "(On)": "(Off)"]
" //Hue.
+
+ menu += "\[Stop\] "
+ menu += "\[Proceed\] "
+ menu += "\[Return Home\]
"
+
+ else
+ menu += "
\[Stop Patrol\] " //patrolon
+ menu += "\[Start Patrol\] " //patroloff
+ menu += "\[Summon Bot\]
" //summon
+ menu += "Keep an ID inserted to upload access codes upon summoning."
+
+ menu += "
Return to bot list"
+ else
+ menu += "
Scan for active bots
"
+ var/turf/current_turf = get_turf(src)
+ var/zlevel = current_turf.z
+ var/botcount = 0
+ for(Bot in GLOB.living_mob_list) //Git da botz
+ if(!Bot.on || Bot.z != zlevel || Bot.remote_disabled || !(bot_access_flags & Bot.bot_type)) //Only non-emagged bots on the same Z-level are detected!
+ continue //Also, the PDA must have access to the bot type.
+ menu += "[Bot.name] ([Bot.get_mode()])
"
+ botcount++
+ if(!botcount) //No bots at all? Lame.
+ menu += "No bots found.
"
+ return
+
+ return menu
diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm
index 3c7464d4dc..185ddf23e6 100644
--- a/code/game/objects/items/robot/robot_upgrades.dm
+++ b/code/game/objects/items/robot/robot_upgrades.dm
@@ -1,403 +1,403 @@
-// robot_upgrades.dm
-// Contains various borg upgrades.
-
-/obj/item/borg/upgrade
- name = "borg upgrade module."
- desc = "Protected by FRM."
- icon = 'icons/obj/module.dmi'
- icon_state = "cyborg_upgrade"
- origin_tech = "programming=2"
- var/locked = 0
- var/installed = 0
- var/require_module = 0
- var/module_type = null
- // if true, is not stored in the robot to be ejected
- // if module is reset
- var/one_use = FALSE
-
-/obj/item/borg/upgrade/proc/action(mob/living/silicon/robot/R)
- if(R.stat == DEAD)
- to_chat(usr, "[src] will not function on a deceased cyborg.")
- return 1
- if(module_type && !istype(R.module, module_type))
- to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!")
- to_chat(usr, "There's no mounting point for the module!")
- return 1
-
-/obj/item/borg/upgrade/rename
- name = "cyborg reclassification board"
- desc = "Used to rename a cyborg."
- icon_state = "cyborg_upgrade1"
- var/heldname = ""
- one_use = TRUE
-
-/obj/item/borg/upgrade/rename/attack_self(mob/user)
- heldname = stripped_input(user, "Enter new robot name", "Cyborg Reclassification", heldname, MAX_NAME_LEN)
-
-/obj/item/borg/upgrade/rename/action(mob/living/silicon/robot/R)
- if(..())
- return
-
- var/oldname = R.real_name
-
- R.custom_name = heldname
- R.updatename()
- if(oldname == R.real_name)
- R.notify_ai(RENAME, oldname, R.real_name)
-
- return 1
-
-
-/obj/item/borg/upgrade/restart
- name = "cyborg emergency reboot module"
- desc = "Used to force a reboot of a disabled-but-repaired cyborg, bringing it back online."
- icon_state = "cyborg_upgrade1"
- one_use = TRUE
-
-/obj/item/borg/upgrade/restart/action(mob/living/silicon/robot/R)
- if(R.health < 0)
- to_chat(usr, "You have to repair the cyborg before using this module!")
- return 0
-
- if(R.mind)
- R.mind.grab_ghost()
- playsound(loc, 'sound/voice/liveagain.ogg', 75, 1)
-
- R.revive()
-
- return 1
-
-/obj/item/borg/upgrade/vtec
- name = "cyborg VTEC module"
- desc = "Used to kick in a cyborg's VTEC systems, increasing their speed."
- icon_state = "cyborg_upgrade2"
- require_module = 1
- origin_tech = "engineering=4;materials=5;programming=4"
-
-/obj/item/borg/upgrade/vtec/action(mob/living/silicon/robot/R)
- if(..())
- return
- if(R.speed < 0)
- to_chat(R, "A VTEC unit is already installed!")
- to_chat(usr, "There's no room for another VTEC unit!")
- return
-
- R.speed = -2 // Gotta go fast.
-
- return 1
-
-/obj/item/borg/upgrade/disablercooler
- name = "cyborg rapid disabler cooling module"
- desc = "Used to cool a mounted disabler, increasing the potential current in it and thus its recharge rate."
- icon_state = "cyborg_upgrade3"
- require_module = 1
- module_type = /obj/item/weapon/robot_module/security
- origin_tech = "engineering=4;powerstorage=4;combat=4"
-
-/obj/item/borg/upgrade/disablercooler/action(mob/living/silicon/robot/R)
- if(..())
- return
-
- var/obj/item/weapon/gun/energy/disabler/cyborg/T = locate() in R.module.modules
- if(!T)
- to_chat(usr, "There's no disabler in this unit!")
- return
- if(T.charge_delay <= 2)
- to_chat(R, "A cooling unit is already installed!")
- to_chat(usr, "There's no room for another cooling unit!")
- return
-
- T.charge_delay = max(2 , T.charge_delay - 4)
-
- return 1
-
-/obj/item/borg/upgrade/thrusters
- name = "ion thruster upgrade"
- desc = "A energy-operated thruster system for cyborgs."
- icon_state = "cyborg_upgrade3"
- origin_tech = "engineering=4;powerstorage=4"
-
-/obj/item/borg/upgrade/thrusters/action(mob/living/silicon/robot/R)
- if(..())
- return
-
- if(R.ionpulse)
- to_chat(usr, "This unit already has ion thrusters installed!")
- return
-
- R.ionpulse = TRUE
- return 1
-
-/obj/item/borg/upgrade/ddrill
- name = "mining cyborg diamond drill"
- desc = "A diamond drill replacement for the mining module's standard drill."
- icon_state = "cyborg_upgrade3"
- require_module = 1
- module_type = /obj/item/weapon/robot_module/miner
- origin_tech = "engineering=4;materials=5"
-
-/obj/item/borg/upgrade/ddrill/action(mob/living/silicon/robot/R)
- if(..())
- return
-
- for(var/obj/item/weapon/pickaxe/drill/cyborg/D in R.module)
- R.module.remove_module(D, TRUE)
- for(var/obj/item/weapon/shovel/S in R.module)
- R.module.remove_module(S, TRUE)
-
- var/obj/item/weapon/pickaxe/drill/cyborg/diamond/DD = new /obj/item/weapon/pickaxe/drill/cyborg/diamond(R.module)
- R.module.basic_modules += DD
- R.module.add_module(DD, FALSE, TRUE)
- return 1
-
-/obj/item/borg/upgrade/soh
- name = "mining cyborg satchel of holding"
- desc = "A satchel of holding replacement for mining cyborg's ore satchel module."
- icon_state = "cyborg_upgrade3"
- require_module = 1
- module_type = /obj/item/weapon/robot_module/miner
- origin_tech = "engineering=4;materials=4;bluespace=4"
-
-/obj/item/borg/upgrade/soh/action(mob/living/silicon/robot/R)
- if(..())
- return
-
- for(var/obj/item/weapon/storage/bag/ore/cyborg/S in R.module)
- R.module.remove_module(S, TRUE)
-
- var/obj/item/weapon/storage/bag/ore/holding/H = new /obj/item/weapon/storage/bag/ore/holding(R.module)
- R.module.basic_modules += H
- R.module.add_module(H, FALSE, TRUE)
- return 1
-
-/obj/item/borg/upgrade/syndicate
- name = "illegal equipment module"
- desc = "Unlocks the hidden, deadlier functions of a cyborg"
- icon_state = "cyborg_upgrade3"
- require_module = 1
- origin_tech = "combat=4;syndicate=1"
-
-/obj/item/borg/upgrade/syndicate/action(mob/living/silicon/robot/R)
- if(..())
- return
-
- if(R.emagged)
- return
-
- R.SetEmagged(1)
-
- return 1
-
-/obj/item/borg/upgrade/lavaproof
- name = "mining cyborg lavaproof tracks"
- desc = "An upgrade kit to apply specialized coolant systems and insulation layers to mining cyborg tracks, enabling them to withstand exposure to molten rock."
- icon_state = "ash_plating"
- resistance_flags = LAVA_PROOF | FIRE_PROOF
- require_module = 1
- module_type = /obj/item/weapon/robot_module/miner
- origin_tech = "engineering=4;materials=4;plasmatech=4"
-
-/obj/item/borg/upgrade/lavaproof/action(mob/living/silicon/robot/R)
- if(..())
- return
- R.weather_immunities += "lava"
- return 1
-
-/obj/item/borg/upgrade/selfrepair
- name = "self-repair module"
- desc = "This module will repair the cyborg over time."
- icon_state = "cyborg_upgrade5"
- require_module = 1
- var/repair_amount = -1
- var/repair_tick = 1
- var/msg_cooldown = 0
- var/on = 0
- var/powercost = 10
- var/mob/living/silicon/robot/cyborg
- var/datum/action/toggle_action
-
-/obj/item/borg/upgrade/selfrepair/action(mob/living/silicon/robot/R)
- if(..())
- return
-
- var/obj/item/borg/upgrade/selfrepair/U = locate() in R
- if(U)
- to_chat(usr, "This unit is already equipped with a self-repair module.")
- return 0
-
- cyborg = R
- icon_state = "selfrepair_off"
- toggle_action = new /datum/action/item_action/toggle(src)
- toggle_action.Grant(R)
- return 1
-
-/obj/item/borg/upgrade/selfrepair/dropped()
- addtimer(CALLBACK(src, .proc/check_dropped), 1)
-
-/obj/item/borg/upgrade/selfrepair/proc/check_dropped()
- if(loc != cyborg)
- toggle_action.Remove(cyborg)
- QDEL_NULL(toggle_action)
- cyborg = null
- deactivate()
-
-/obj/item/borg/upgrade/selfrepair/ui_action_click()
- on = !on
- if(on)
- to_chat(cyborg, "You activate the self-repair module.")
- START_PROCESSING(SSobj, src)
- else
- to_chat(cyborg, "You deactivate the self-repair module.")
- STOP_PROCESSING(SSobj, src)
- update_icon()
-
-/obj/item/borg/upgrade/selfrepair/update_icon()
- if(cyborg)
- icon_state = "selfrepair_[on ? "on" : "off"]"
- for(var/X in actions)
- var/datum/action/A = X
- A.UpdateButtonIcon()
- else
- icon_state = "cyborg_upgrade5"
-
-/obj/item/borg/upgrade/selfrepair/proc/deactivate()
- STOP_PROCESSING(SSobj, src)
- on = FALSE
- update_icon()
-
-/obj/item/borg/upgrade/selfrepair/process()
- if(!repair_tick)
- repair_tick = 1
- return
-
- if(cyborg && (cyborg.stat != DEAD) && on)
- if(!cyborg.cell)
- to_chat(cyborg, "Self-repair module deactivated. Please, insert the power cell.")
- deactivate()
- return
-
- if(cyborg.cell.charge < powercost * 2)
- to_chat(cyborg, "Self-repair module deactivated. Please recharge.")
- deactivate()
- return
-
- if(cyborg.health < cyborg.maxHealth)
- if(cyborg.health < 0)
- repair_amount = -2.5
- powercost = 30
- else
- repair_amount = -1
- powercost = 10
- cyborg.adjustBruteLoss(repair_amount)
- cyborg.adjustFireLoss(repair_amount)
- cyborg.updatehealth()
- cyborg.cell.use(powercost)
- else
- cyborg.cell.use(5)
- repair_tick = 0
-
- if((world.time - 2000) > msg_cooldown )
- var/msgmode = "standby"
- if(cyborg.health < 0)
- msgmode = "critical"
- else if(cyborg.health < cyborg.maxHealth)
- msgmode = "normal"
- to_chat(cyborg, "Self-repair is active in [msgmode] mode.")
- msg_cooldown = world.time
- else
- deactivate()
-
-/obj/item/borg/upgrade/hypospray
- name = "medical cyborg hypospray advanced synthesiser"
- desc = "An upgrade to the Medical module cyborg's hypospray, allowing it \
- to produce more advanced and complex medical reagents."
- icon_state = "cyborg_upgrade3"
- require_module = 1
- module_type = /obj/item/weapon/robot_module/medical
- origin_tech = null
- var/list/additional_reagents = list()
-
-/obj/item/borg/upgrade/hypospray/action(mob/living/silicon/robot/R)
- if(..())
- return
- for(var/obj/item/weapon/reagent_containers/borghypo/H in R.module)
- if(H.accepts_reagent_upgrades)
- for(var/re in additional_reagents)
- H.add_reagent(re)
-
- return 1
-
-/obj/item/borg/upgrade/hypospray/expanded
- name = "medical cyborg expanded hypospray"
- desc = "An upgrade to the Medical module's hypospray, allowing it \
- to treat a wider range of conditions and problems."
- additional_reagents = list("mannitol", "oculine", "inacusiate",
- "mutadone", "haloperidol")
- origin_tech = "programming=5;engineering=4;biotech=5"
-
-/obj/item/borg/upgrade/hypospray/high_strength
- name = "medical cyborg high-strength hypospray"
- desc = "An upgrade to the Medical module's hypospray, containing \
- stronger versions of existing chemicals."
- additional_reagents = list("oxandrolone", "sal_acid", "rezadone",
- "pen_acid")
- origin_tech = "programming=5;engineering=5;biotech=6"
-
-/obj/item/borg/upgrade/piercing_hypospray
- name = "cyborg piercing hypospray"
- desc = "An upgrade to a cyborg's hypospray, allowing it to \
- pierce armor and thick material."
- origin_tech = "materials=5;engineering=7;combat=3"
- icon_state = "cyborg_upgrade3"
-
-/obj/item/borg/upgrade/piercing_hypospray/action(mob/living/silicon/robot/R)
- if(..())
- return
-
- var/found_hypo = FALSE
- for(var/obj/item/weapon/reagent_containers/borghypo/H in R.module)
- H.bypass_protection = TRUE
- found_hypo = TRUE
-
- if(!found_hypo)
- return
-
- return 1
-
-/obj/item/borg/upgrade/defib
- name = "medical cyborg defibrillator"
- desc = "An upgrade to the Medical module, installing a builtin \
- defibrillator, for on the scene revival."
- icon_state = "cyborg_upgrade3"
- require_module = 1
- module_type = /obj/item/weapon/robot_module/medical
- origin_tech = "programming=4;engineering=6;materials=5;powerstorage=5;biotech=5"
-
-/obj/item/borg/upgrade/defib/action(mob/living/silicon/robot/R)
- if(..())
- return
-
- var/obj/item/weapon/twohanded/shockpaddles/cyborg/S = new(R.module)
- R.module.basic_modules += S
- R.module.add_module(S, FALSE, TRUE)
-
- return 1
-
-/obj/item/borg/upgrade/ai
- name = "B.O.R.I.S. module"
- desc = "Bluespace Optimized Remote Intelligence Synchronization. An uplink device which takes the place of an MMI in cyborg endoskeletons, creating a robotic shell controlled by an AI."
- icon_state = "boris"
- origin_tech = "engineering=4;magnets=4;programming=4"
-
-/obj/item/borg/upgrade/ai/action(mob/living/silicon/robot/R)
- if(..())
- return
- if(R.shell)
- to_chat(usr, "This unit is already an AI shell!")
- return
- if(R.key) //You cannot replace a player unless the key is completely removed.
- to_chat(usr, "Intelligence patterns detected in this [R.braintype]. Aborting.")
- return
-
- R.make_shell(src)
- return TRUE
+// robot_upgrades.dm
+// Contains various borg upgrades.
+
+/obj/item/borg/upgrade
+ name = "borg upgrade module."
+ desc = "Protected by FRM."
+ icon = 'icons/obj/module.dmi'
+ icon_state = "cyborg_upgrade"
+ origin_tech = "programming=2"
+ var/locked = 0
+ var/installed = 0
+ var/require_module = 0
+ var/module_type = null
+ // if true, is not stored in the robot to be ejected
+ // if module is reset
+ var/one_use = FALSE
+
+/obj/item/borg/upgrade/proc/action(mob/living/silicon/robot/R)
+ if(R.stat == DEAD)
+ to_chat(usr, "[src] will not function on a deceased cyborg.")
+ return 1
+ if(module_type && !istype(R.module, module_type))
+ to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!")
+ to_chat(usr, "There's no mounting point for the module!")
+ return 1
+
+/obj/item/borg/upgrade/rename
+ name = "cyborg reclassification board"
+ desc = "Used to rename a cyborg."
+ icon_state = "cyborg_upgrade1"
+ var/heldname = ""
+ one_use = TRUE
+
+/obj/item/borg/upgrade/rename/attack_self(mob/user)
+ heldname = stripped_input(user, "Enter new robot name", "Cyborg Reclassification", heldname, MAX_NAME_LEN)
+
+/obj/item/borg/upgrade/rename/action(mob/living/silicon/robot/R)
+ if(..())
+ return
+
+ var/oldname = R.real_name
+
+ R.custom_name = heldname
+ R.updatename()
+ if(oldname == R.real_name)
+ R.notify_ai(RENAME, oldname, R.real_name)
+
+ return 1
+
+
+/obj/item/borg/upgrade/restart
+ name = "cyborg emergency reboot module"
+ desc = "Used to force a reboot of a disabled-but-repaired cyborg, bringing it back online."
+ icon_state = "cyborg_upgrade1"
+ one_use = TRUE
+
+/obj/item/borg/upgrade/restart/action(mob/living/silicon/robot/R)
+ if(R.health < 0)
+ to_chat(usr, "You have to repair the cyborg before using this module!")
+ return 0
+
+ if(R.mind)
+ R.mind.grab_ghost()
+ playsound(loc, 'sound/voice/liveagain.ogg', 75, 1)
+
+ R.revive()
+
+ return 1
+
+/obj/item/borg/upgrade/vtec
+ name = "cyborg VTEC module"
+ desc = "Used to kick in a cyborg's VTEC systems, increasing their speed."
+ icon_state = "cyborg_upgrade2"
+ require_module = 1
+ origin_tech = "engineering=4;materials=5;programming=4"
+
+/obj/item/borg/upgrade/vtec/action(mob/living/silicon/robot/R)
+ if(..())
+ return
+ if(R.speed < 0)
+ to_chat(R, "A VTEC unit is already installed!")
+ to_chat(usr, "There's no room for another VTEC unit!")
+ return
+
+ R.speed = -2 // Gotta go fast.
+
+ return 1
+
+/obj/item/borg/upgrade/disablercooler
+ name = "cyborg rapid disabler cooling module"
+ desc = "Used to cool a mounted disabler, increasing the potential current in it and thus its recharge rate."
+ icon_state = "cyborg_upgrade3"
+ require_module = 1
+ module_type = /obj/item/weapon/robot_module/security
+ origin_tech = "engineering=4;powerstorage=4;combat=4"
+
+/obj/item/borg/upgrade/disablercooler/action(mob/living/silicon/robot/R)
+ if(..())
+ return
+
+ var/obj/item/weapon/gun/energy/disabler/cyborg/T = locate() in R.module.modules
+ if(!T)
+ to_chat(usr, "There's no disabler in this unit!")
+ return
+ if(T.charge_delay <= 2)
+ to_chat(R, "A cooling unit is already installed!")
+ to_chat(usr, "There's no room for another cooling unit!")
+ return
+
+ T.charge_delay = max(2 , T.charge_delay - 4)
+
+ return 1
+
+/obj/item/borg/upgrade/thrusters
+ name = "ion thruster upgrade"
+ desc = "A energy-operated thruster system for cyborgs."
+ icon_state = "cyborg_upgrade3"
+ origin_tech = "engineering=4;powerstorage=4"
+
+/obj/item/borg/upgrade/thrusters/action(mob/living/silicon/robot/R)
+ if(..())
+ return
+
+ if(R.ionpulse)
+ to_chat(usr, "This unit already has ion thrusters installed!")
+ return
+
+ R.ionpulse = TRUE
+ return 1
+
+/obj/item/borg/upgrade/ddrill
+ name = "mining cyborg diamond drill"
+ desc = "A diamond drill replacement for the mining module's standard drill."
+ icon_state = "cyborg_upgrade3"
+ require_module = 1
+ module_type = /obj/item/weapon/robot_module/miner
+ origin_tech = "engineering=4;materials=5"
+
+/obj/item/borg/upgrade/ddrill/action(mob/living/silicon/robot/R)
+ if(..())
+ return
+
+ for(var/obj/item/weapon/pickaxe/drill/cyborg/D in R.module)
+ R.module.remove_module(D, TRUE)
+ for(var/obj/item/weapon/shovel/S in R.module)
+ R.module.remove_module(S, TRUE)
+
+ var/obj/item/weapon/pickaxe/drill/cyborg/diamond/DD = new /obj/item/weapon/pickaxe/drill/cyborg/diamond(R.module)
+ R.module.basic_modules += DD
+ R.module.add_module(DD, FALSE, TRUE)
+ return 1
+
+/obj/item/borg/upgrade/soh
+ name = "mining cyborg satchel of holding"
+ desc = "A satchel of holding replacement for mining cyborg's ore satchel module."
+ icon_state = "cyborg_upgrade3"
+ require_module = 1
+ module_type = /obj/item/weapon/robot_module/miner
+ origin_tech = "engineering=4;materials=4;bluespace=4"
+
+/obj/item/borg/upgrade/soh/action(mob/living/silicon/robot/R)
+ if(..())
+ return
+
+ for(var/obj/item/weapon/storage/bag/ore/cyborg/S in R.module)
+ R.module.remove_module(S, TRUE)
+
+ var/obj/item/weapon/storage/bag/ore/holding/H = new /obj/item/weapon/storage/bag/ore/holding(R.module)
+ R.module.basic_modules += H
+ R.module.add_module(H, FALSE, TRUE)
+ return 1
+
+/obj/item/borg/upgrade/syndicate
+ name = "illegal equipment module"
+ desc = "Unlocks the hidden, deadlier functions of a cyborg"
+ icon_state = "cyborg_upgrade3"
+ require_module = 1
+ origin_tech = "combat=4;syndicate=1"
+
+/obj/item/borg/upgrade/syndicate/action(mob/living/silicon/robot/R)
+ if(..())
+ return
+
+ if(R.emagged)
+ return
+
+ R.SetEmagged(1)
+
+ return 1
+
+/obj/item/borg/upgrade/lavaproof
+ name = "mining cyborg lavaproof tracks"
+ desc = "An upgrade kit to apply specialized coolant systems and insulation layers to mining cyborg tracks, enabling them to withstand exposure to molten rock."
+ icon_state = "ash_plating"
+ resistance_flags = LAVA_PROOF | FIRE_PROOF
+ require_module = 1
+ module_type = /obj/item/weapon/robot_module/miner
+ origin_tech = "engineering=4;materials=4;plasmatech=4"
+
+/obj/item/borg/upgrade/lavaproof/action(mob/living/silicon/robot/R)
+ if(..())
+ return
+ R.weather_immunities += "lava"
+ return 1
+
+/obj/item/borg/upgrade/selfrepair
+ name = "self-repair module"
+ desc = "This module will repair the cyborg over time."
+ icon_state = "cyborg_upgrade5"
+ require_module = 1
+ var/repair_amount = -1
+ var/repair_tick = 1
+ var/msg_cooldown = 0
+ var/on = 0
+ var/powercost = 10
+ var/mob/living/silicon/robot/cyborg
+ var/datum/action/toggle_action
+
+/obj/item/borg/upgrade/selfrepair/action(mob/living/silicon/robot/R)
+ if(..())
+ return
+
+ var/obj/item/borg/upgrade/selfrepair/U = locate() in R
+ if(U)
+ to_chat(usr, "This unit is already equipped with a self-repair module.")
+ return 0
+
+ cyborg = R
+ icon_state = "selfrepair_off"
+ toggle_action = new /datum/action/item_action/toggle(src)
+ toggle_action.Grant(R)
+ return 1
+
+/obj/item/borg/upgrade/selfrepair/dropped()
+ addtimer(CALLBACK(src, .proc/check_dropped), 1)
+
+/obj/item/borg/upgrade/selfrepair/proc/check_dropped()
+ if(loc != cyborg)
+ toggle_action.Remove(cyborg)
+ QDEL_NULL(toggle_action)
+ cyborg = null
+ deactivate()
+
+/obj/item/borg/upgrade/selfrepair/ui_action_click()
+ on = !on
+ if(on)
+ to_chat(cyborg, "You activate the self-repair module.")
+ START_PROCESSING(SSobj, src)
+ else
+ to_chat(cyborg, "You deactivate the self-repair module.")
+ STOP_PROCESSING(SSobj, src)
+ update_icon()
+
+/obj/item/borg/upgrade/selfrepair/update_icon()
+ if(cyborg)
+ icon_state = "selfrepair_[on ? "on" : "off"]"
+ for(var/X in actions)
+ var/datum/action/A = X
+ A.UpdateButtonIcon()
+ else
+ icon_state = "cyborg_upgrade5"
+
+/obj/item/borg/upgrade/selfrepair/proc/deactivate()
+ STOP_PROCESSING(SSobj, src)
+ on = FALSE
+ update_icon()
+
+/obj/item/borg/upgrade/selfrepair/process()
+ if(!repair_tick)
+ repair_tick = 1
+ return
+
+ if(cyborg && (cyborg.stat != DEAD) && on)
+ if(!cyborg.cell)
+ to_chat(cyborg, "Self-repair module deactivated. Please, insert the power cell.")
+ deactivate()
+ return
+
+ if(cyborg.cell.charge < powercost * 2)
+ to_chat(cyborg, "Self-repair module deactivated. Please recharge.")
+ deactivate()
+ return
+
+ if(cyborg.health < cyborg.maxHealth)
+ if(cyborg.health < 0)
+ repair_amount = -2.5
+ powercost = 30
+ else
+ repair_amount = -1
+ powercost = 10
+ cyborg.adjustBruteLoss(repair_amount)
+ cyborg.adjustFireLoss(repair_amount)
+ cyborg.updatehealth()
+ cyborg.cell.use(powercost)
+ else
+ cyborg.cell.use(5)
+ repair_tick = 0
+
+ if((world.time - 2000) > msg_cooldown )
+ var/msgmode = "standby"
+ if(cyborg.health < 0)
+ msgmode = "critical"
+ else if(cyborg.health < cyborg.maxHealth)
+ msgmode = "normal"
+ to_chat(cyborg, "Self-repair is active in [msgmode] mode.")
+ msg_cooldown = world.time
+ else
+ deactivate()
+
+/obj/item/borg/upgrade/hypospray
+ name = "medical cyborg hypospray advanced synthesiser"
+ desc = "An upgrade to the Medical module cyborg's hypospray, allowing it \
+ to produce more advanced and complex medical reagents."
+ icon_state = "cyborg_upgrade3"
+ require_module = 1
+ module_type = /obj/item/weapon/robot_module/medical
+ origin_tech = null
+ var/list/additional_reagents = list()
+
+/obj/item/borg/upgrade/hypospray/action(mob/living/silicon/robot/R)
+ if(..())
+ return
+ for(var/obj/item/weapon/reagent_containers/borghypo/H in R.module)
+ if(H.accepts_reagent_upgrades)
+ for(var/re in additional_reagents)
+ H.add_reagent(re)
+
+ return 1
+
+/obj/item/borg/upgrade/hypospray/expanded
+ name = "medical cyborg expanded hypospray"
+ desc = "An upgrade to the Medical module's hypospray, allowing it \
+ to treat a wider range of conditions and problems."
+ additional_reagents = list("mannitol", "oculine", "inacusiate",
+ "mutadone", "haloperidol")
+ origin_tech = "programming=5;engineering=4;biotech=5"
+
+/obj/item/borg/upgrade/hypospray/high_strength
+ name = "medical cyborg high-strength hypospray"
+ desc = "An upgrade to the Medical module's hypospray, containing \
+ stronger versions of existing chemicals."
+ additional_reagents = list("oxandrolone", "sal_acid", "rezadone",
+ "pen_acid")
+ origin_tech = "programming=5;engineering=5;biotech=6"
+
+/obj/item/borg/upgrade/piercing_hypospray
+ name = "cyborg piercing hypospray"
+ desc = "An upgrade to a cyborg's hypospray, allowing it to \
+ pierce armor and thick material."
+ origin_tech = "materials=5;engineering=7;combat=3"
+ icon_state = "cyborg_upgrade3"
+
+/obj/item/borg/upgrade/piercing_hypospray/action(mob/living/silicon/robot/R)
+ if(..())
+ return
+
+ var/found_hypo = FALSE
+ for(var/obj/item/weapon/reagent_containers/borghypo/H in R.module)
+ H.bypass_protection = TRUE
+ found_hypo = TRUE
+
+ if(!found_hypo)
+ return
+
+ return 1
+
+/obj/item/borg/upgrade/defib
+ name = "medical cyborg defibrillator"
+ desc = "An upgrade to the Medical module, installing a builtin \
+ defibrillator, for on the scene revival."
+ icon_state = "cyborg_upgrade3"
+ require_module = 1
+ module_type = /obj/item/weapon/robot_module/medical
+ origin_tech = "programming=4;engineering=6;materials=5;powerstorage=5;biotech=5"
+
+/obj/item/borg/upgrade/defib/action(mob/living/silicon/robot/R)
+ if(..())
+ return
+
+ var/obj/item/weapon/twohanded/shockpaddles/cyborg/S = new(R.module)
+ R.module.basic_modules += S
+ R.module.add_module(S, FALSE, TRUE)
+
+ return 1
+
+/obj/item/borg/upgrade/ai
+ name = "B.O.R.I.S. module"
+ desc = "Bluespace Optimized Remote Intelligence Synchronization. An uplink device which takes the place of an MMI in cyborg endoskeletons, creating a robotic shell controlled by an AI."
+ icon_state = "boris"
+ origin_tech = "engineering=4;magnets=4;programming=4"
+
+/obj/item/borg/upgrade/ai/action(mob/living/silicon/robot/R)
+ if(..())
+ return
+ if(R.shell)
+ to_chat(usr, "This unit is already an AI shell!")
+ return
+ if(R.key) //You cannot replace a player unless the key is completely removed.
+ to_chat(usr, "Intelligence patterns detected in this [R.braintype]. Aborting.")
+ return
+
+ R.make_shell(src)
+ return TRUE
diff --git a/code/game/objects/items/weapons/grenades/spawnergrenade.dm b/code/game/objects/items/weapons/grenades/spawnergrenade.dm
index f0566e06a0..d53b87f5f2 100644
--- a/code/game/objects/items/weapons/grenades/spawnergrenade.dm
+++ b/code/game/objects/items/weapons/grenades/spawnergrenade.dm
@@ -1,39 +1,39 @@
-/obj/item/weapon/grenade/spawnergrenade
- desc = "It will unleash an unspecified anomaly into the vicinity."
- name = "delivery grenade"
- icon = 'icons/obj/grenade.dmi'
- icon_state = "delivery"
- item_state = "flashbang"
- origin_tech = "materials=3;magnets=4"
- var/spawner_type = null // must be an object path
- var/deliveryamt = 1 // amount of type to deliver
-
-/obj/item/weapon/grenade/spawnergrenade/prime() // Prime now just handles the two loops that query for people in lockers and people who can see it.
- update_mob()
- if(spawner_type && deliveryamt)
- // Make a quick flash
- var/turf/T = get_turf(src)
- playsound(T, 'sound/effects/phasein.ogg', 100, 1)
- for(var/mob/living/carbon/C in viewers(T, null))
- C.flash_act()
-
- // Spawn some hostile syndicate critters and spread them out
- spawn_and_random_walk(spawner_type, T, deliveryamt, walk_chance=50, admin_spawn=admin_spawned)
-
- qdel(src)
-
-/obj/item/weapon/grenade/spawnergrenade/manhacks
- name = "viscerator delivery grenade"
- spawner_type = /mob/living/simple_animal/hostile/viscerator
- deliveryamt = 10
- origin_tech = "materials=3;magnets=4;syndicate=3"
-
-/obj/item/weapon/grenade/spawnergrenade/spesscarp
- name = "carp delivery grenade"
- spawner_type = /mob/living/simple_animal/hostile/carp
- deliveryamt = 5
- origin_tech = "materials=3;magnets=4;syndicate=3"
-
-/obj/item/weapon/grenade/spawnergrenade/syndiesoap
- name = "Mister Scrubby"
- spawner_type = /obj/item/weapon/soap/syndie
+/obj/item/weapon/grenade/spawnergrenade
+ desc = "It will unleash an unspecified anomaly into the vicinity."
+ name = "delivery grenade"
+ icon = 'icons/obj/grenade.dmi'
+ icon_state = "delivery"
+ item_state = "flashbang"
+ origin_tech = "materials=3;magnets=4"
+ var/spawner_type = null // must be an object path
+ var/deliveryamt = 1 // amount of type to deliver
+
+/obj/item/weapon/grenade/spawnergrenade/prime() // Prime now just handles the two loops that query for people in lockers and people who can see it.
+ update_mob()
+ if(spawner_type && deliveryamt)
+ // Make a quick flash
+ var/turf/T = get_turf(src)
+ playsound(T, 'sound/effects/phasein.ogg', 100, 1)
+ for(var/mob/living/carbon/C in viewers(T, null))
+ C.flash_act()
+
+ // Spawn some hostile syndicate critters and spread them out
+ spawn_and_random_walk(spawner_type, T, deliveryamt, walk_chance=50, admin_spawn=admin_spawned)
+
+ qdel(src)
+
+/obj/item/weapon/grenade/spawnergrenade/manhacks
+ name = "viscerator delivery grenade"
+ spawner_type = /mob/living/simple_animal/hostile/viscerator
+ deliveryamt = 10
+ origin_tech = "materials=3;magnets=4;syndicate=3"
+
+/obj/item/weapon/grenade/spawnergrenade/spesscarp
+ name = "carp delivery grenade"
+ spawner_type = /mob/living/simple_animal/hostile/carp
+ deliveryamt = 5
+ origin_tech = "materials=3;magnets=4;syndicate=3"
+
+/obj/item/weapon/grenade/spawnergrenade/syndiesoap
+ name = "Mister Scrubby"
+ spawner_type = /obj/item/weapon/soap/syndie
diff --git a/code/game/objects/items/weapons/storage/uplink_kits.dm b/code/game/objects/items/weapons/storage/uplink_kits.dm
index 1962fbd818..90e7d1be1a 100644
--- a/code/game/objects/items/weapons/storage/uplink_kits.dm
+++ b/code/game/objects/items/weapons/storage/uplink_kits.dm
@@ -1,305 +1,305 @@
-/obj/item/weapon/storage/box/syndicate
-
-/obj/item/weapon/storage/box/syndicate/PopulateContents()
- switch (pickweight(list("bloodyspai" = 3, "stealth" = 2, "bond" = 2, "screwed" = 2, "sabotage" = 3, "guns" = 2, "murder" = 2, "implant" = 1, "hacker" = 3, "darklord" = 1, "sniper" = 1, "metaops" = 1, "ninja" = 1)))
- if("bloodyspai") // 27 tc now this is more right
- new /obj/item/clothing/under/chameleon(src) // 2 tc since it's not the full set
- new /obj/item/clothing/mask/chameleon(src) // Goes with above
- new /obj/item/weapon/card/id/syndicate(src) // 2 tc
- new /obj/item/clothing/shoes/chameleon(src) // 2 tc
- new /obj/item/device/camera_bug(src) // 1 tc
- new /obj/item/device/multitool/ai_detect(src) // 1 tc
- new /obj/item/device/encryptionkey/syndicate(src) // 2 tc
- new /obj/item/weapon/reagent_containers/syringe/mulligan(src) // 4 tc
- new /obj/item/weapon/switchblade(src) //I'll count this as 2 tc
- new /obj/item/weapon/storage/fancy/cigarettes/cigpack_syndicate (src) // 2 tc this shit heals
- new /obj/item/device/flashlight/emp(src) // 2 tc
- new /obj/item/device/chameleon(src) // 7 tc
-
- if("stealth") // 31 tc
- new /obj/item/weapon/gun/energy/kinetic_accelerator/crossbow(src)
- new /obj/item/weapon/pen/sleepy(src)
- new /obj/item/device/healthanalyzer/rad_laser(src)
- new /obj/item/device/chameleon(src)
- new /obj/item/weapon/soap/syndie(src)
- new /obj/item/clothing/glasses/thermal/syndi(src)
-
- if("bond") // 29 tc
- new /obj/item/weapon/gun/ballistic/automatic/pistol(src)
- new /obj/item/weapon/suppressor(src)
- new /obj/item/ammo_box/magazine/m10mm(src)
- new /obj/item/ammo_box/magazine/m10mm(src)
- new /obj/item/clothing/under/chameleon(src)
- new /obj/item/weapon/card/id/syndicate(src)
- new /obj/item/weapon/reagent_containers/syringe/stimulants(src)
-
- if("screwed") // 29 tc
- new /obj/item/device/sbeacondrop/bomb(src)
- new /obj/item/weapon/grenade/syndieminibomb(src)
- new /obj/item/device/sbeacondrop/powersink(src)
- new /obj/item/clothing/suit/space/syndicate/black/red(src)
- new /obj/item/clothing/head/helmet/space/syndicate/black/red(src)
- new /obj/item/device/encryptionkey/syndicate(src)
-
- if("guns") // 28 tc now
- new /obj/item/weapon/gun/ballistic/revolver(src)
- new /obj/item/ammo_box/a357(src)
- new /obj/item/ammo_box/a357(src)
- new /obj/item/weapon/card/emag(src)
- new /obj/item/weapon/grenade/plastic/c4(src)
- new /obj/item/clothing/gloves/color/latex/nitrile(src)
- new /obj/item/clothing/mask/gas/clown_hat(src)
- new /obj/item/clothing/under/suit_jacket/really_black(src)
-
- if("murder") // 28 tc now
- new /obj/item/weapon/melee/energy/sword/saber(src)
- new /obj/item/clothing/glasses/thermal/syndi(src)
- new /obj/item/weapon/card/emag(src)
- new /obj/item/clothing/shoes/chameleon(src)
- new /obj/item/device/encryptionkey/syndicate(src)
- new /obj/item/weapon/grenade/syndieminibomb(src)
-
- if("implant") // 55+ tc holy shit what the fuck this is a lottery disguised as fun boxes isn't it?
- new /obj/item/weapon/implanter/freedom(src)
- new /obj/item/weapon/implanter/uplink/precharged(src)
- new /obj/item/weapon/implanter/emp(src)
- new /obj/item/weapon/implanter/adrenalin(src)
- new /obj/item/weapon/implanter/explosive(src)
- new /obj/item/weapon/implanter/storage(src)
-
- if("hacker") // 26 tc
- new /obj/item/weapon/aiModule/syndicate(src)
- new /obj/item/weapon/card/emag(src)
- new /obj/item/device/encryptionkey/binary(src)
- new /obj/item/weapon/aiModule/toyAI(src)
- new /obj/item/device/multitool/ai_detect(src)
-
- if("lordsingulo") // 24 tc
- new /obj/item/device/sbeacondrop(src)
- new /obj/item/clothing/suit/space/syndicate/black/red(src)
- new /obj/item/clothing/head/helmet/space/syndicate/black/red(src)
- new /obj/item/weapon/card/emag(src)
-
- if("sabotage") // 26 tc now
- new /obj/item/weapon/grenade/plastic/c4 (src)
- new /obj/item/weapon/grenade/plastic/c4 (src)
- new /obj/item/device/doorCharge(src)
- new /obj/item/device/doorCharge(src)
- new /obj/item/device/camera_bug(src)
- new /obj/item/device/sbeacondrop/powersink(src)
- new /obj/item/weapon/cartridge/syndicate(src)
- new /obj/item/weapon/storage/toolbox/syndicate(src) //To actually get to those places
- new /obj/item/pizzabox/bomb
-
- if("darklord") //20 tc + tk + summon item close enough for now
- new /obj/item/weapon/twohanded/dualsaber(src)
- new /obj/item/weapon/dnainjector/telemut/darkbundle(src)
- new /obj/item/clothing/suit/hooded/chaplain_hoodie(src)
- new /obj/item/weapon/card/id/syndicate(src)
- new /obj/item/clothing/shoes/chameleon(src) //because slipping while being a dark lord sucks
- new /obj/item/weapon/spellbook/oneuse/summonitem(src)
-
- if("sniper") //This shit is unique so can't really balance it around tc, also no silencer because getting killed without ANY indicator on what killed you sucks
- new /obj/item/weapon/gun/ballistic/automatic/sniper_rifle(src) // 12 tc
- new /obj/item/ammo_box/magazine/sniper_rounds/penetrator(src)
- new /obj/item/clothing/glasses/thermal/syndi(src)
- new /obj/item/clothing/gloves/color/latex/nitrile(src)
- new /obj/item/clothing/mask/gas/clown_hat(src)
- new /obj/item/clothing/under/suit_jacket/really_black(src)
-
- if("metaops") // 30 tc
- new /obj/item/clothing/suit/space/hardsuit/syndi(src) // 8 tc
- new /obj/item/weapon/gun/ballistic/automatic/shotgun/bulldog/unrestricted(src) // 8 tc
- new /obj/item/weapon/implanter/explosive(src) // 2 tc
- new /obj/item/ammo_box/magazine/m12g/buckshot(src) // 2 tc
- new /obj/item/ammo_box/magazine/m12g/buckshot(src) // 2 tc
- new /obj/item/weapon/grenade/plastic/c4 (src) // 1 tc
- new /obj/item/weapon/grenade/plastic/c4 (src) // 1 tc
- new /obj/item/weapon/card/emag(src) // 6 tc
-
- if("ninja") // 33 tc worth
- new /obj/item/weapon/katana(src) // Unique , hard to tell how much tc this is worth. 8 tc?
- new /obj/item/weapon/implanter/adrenalin(src) // 8 tc
- new /obj/item/weapon/throwing_star(src) // ~5 tc for all 6
- new /obj/item/weapon/throwing_star(src)
- new /obj/item/weapon/throwing_star(src)
- new /obj/item/weapon/throwing_star(src)
- new /obj/item/weapon/throwing_star(src)
- new /obj/item/weapon/throwing_star(src)
- new /obj/item/weapon/storage/belt/chameleon(src) // Unique but worth at least 2 tc
- new /obj/item/weapon/card/id/syndicate(src) // 2 tc
- new /obj/item/device/chameleon(src) // 7 tc
-
-/obj/item/weapon/storage/box/syndie_kit
- name = "box"
- desc = "A sleek, sturdy box."
- icon_state = "syndiebox"
- illustration = "writing_syndie"
-
-/obj/item/weapon/storage/box/syndie_kit/imp_freedom
- name = "boxed freedom implant (with injector)"
-
-/obj/item/weapon/storage/box/syndie_kit/imp_freedom/PopulateContents()
- var/obj/item/weapon/implanter/O = new(src)
- O.imp = new /obj/item/weapon/implant/freedom(O)
- O.update_icon()
-
-/obj/item/weapon/storage/box/syndie_kit/imp_microbomb
- name = "Microbomb Implant (with injector)"
-
-/obj/item/weapon/storage/box/syndie_kit/imp_microbomb/PopulateContents()
- var/obj/item/weapon/implanter/O = new(src)
- O.imp = new /obj/item/weapon/implant/explosive(O)
- O.update_icon()
-
-/obj/item/weapon/storage/box/syndie_kit/imp_macrobomb
- name = "Macrobomb Implant (with injector)"
-
-/obj/item/weapon/storage/box/syndie_kit/imp_macrobomb/PopulateContents()
- var/obj/item/weapon/implanter/O = new(src)
- O.imp = new /obj/item/weapon/implant/explosive/macro(O)
- O.update_icon()
-
-/obj/item/weapon/storage/box/syndie_kit/imp_uplink
- name = "boxed uplink implant (with injector)"
-
-/obj/item/weapon/storage/box/syndie_kit/imp_uplink/PopulateContents()
- ..()
- var/obj/item/weapon/implanter/O = new(src)
- O.imp = new /obj/item/weapon/implant/uplink(O)
- O.update_icon()
-
-/obj/item/weapon/storage/box/syndie_kit/bioterror
- name = "bioterror syringe box"
-
-/obj/item/weapon/storage/box/syndie_kit/bioterror/PopulateContents()
- for(var/i in 1 to 7)
- new /obj/item/weapon/reagent_containers/syringe/bioterror(src)
-
-/obj/item/weapon/storage/box/syndie_kit/imp_adrenal
- name = "boxed adrenal implant (with injector)"
-
-/obj/item/weapon/storage/box/syndie_kit/imp_adrenal/PopulateContents()
- var/obj/item/weapon/implanter/O = new(src)
- O.imp = new /obj/item/weapon/implant/adrenalin(O)
- O.update_icon()
-
-/obj/item/weapon/storage/box/syndie_kit/imp_storage
- name = "boxed storage implant (with injector)"
-
-/obj/item/weapon/storage/box/syndie_kit/imp_storage/PopulateContents()
- new /obj/item/weapon/implanter/storage(src)
-
-/obj/item/weapon/storage/box/syndie_kit/space
- name = "boxed space suit and helmet"
- can_hold = list(/obj/item/clothing/suit/space/syndicate, /obj/item/clothing/head/helmet/space/syndicate)
- max_w_class = WEIGHT_CLASS_NORMAL
-
-/obj/item/weapon/storage/box/syndie_kit/space/PopulateContents()
- new /obj/item/clothing/suit/space/syndicate/black/red(src) // Black and red is so in right now
- new /obj/item/clothing/head/helmet/space/syndicate/black/red(src)
-
-/obj/item/weapon/storage/box/syndie_kit/emp
- name = "boxed EMP kit"
-
-/obj/item/weapon/storage/box/syndie_kit/emp/PopulateContents()
- new /obj/item/weapon/grenade/empgrenade(src)
- new /obj/item/weapon/grenade/empgrenade(src)
- new /obj/item/weapon/grenade/empgrenade(src)
- new /obj/item/weapon/grenade/empgrenade(src)
- new /obj/item/weapon/grenade/empgrenade(src)
- new /obj/item/weapon/implanter/emp(src)
-
-/obj/item/weapon/storage/box/syndie_kit/chemical
- name = "boxed chemical kit"
- storage_slots = 14
-
-/obj/item/weapon/storage/box/syndie_kit/chemical/PopulateContents()
- new /obj/item/weapon/reagent_containers/glass/bottle/polonium(src)
- new /obj/item/weapon/reagent_containers/glass/bottle/venom(src)
- new /obj/item/weapon/reagent_containers/glass/bottle/neurotoxin2(src)
- new /obj/item/weapon/reagent_containers/glass/bottle/formaldehyde(src)
- new /obj/item/weapon/reagent_containers/glass/bottle/spewium(src)
- new /obj/item/weapon/reagent_containers/glass/bottle/cyanide(src)
- new /obj/item/weapon/reagent_containers/glass/bottle/histamine(src)
- new /obj/item/weapon/reagent_containers/glass/bottle/initropidril(src)
- new /obj/item/weapon/reagent_containers/glass/bottle/pancuronium(src)
- new /obj/item/weapon/reagent_containers/glass/bottle/sodium_thiopental(src)
- new /obj/item/weapon/reagent_containers/glass/bottle/coniine(src)
- new /obj/item/weapon/reagent_containers/glass/bottle/curare(src)
- new /obj/item/weapon/reagent_containers/glass/bottle/amanitin(src)
- new /obj/item/weapon/reagent_containers/syringe(src)
-
-/obj/item/weapon/storage/box/syndie_kit/nuke
- name = "box"
-
-/obj/item/weapon/storage/box/syndie_kit/nuke/PopulateContents()
- new /obj/item/weapon/screwdriver/nuke(src)
- new /obj/item/nuke_core_container(src)
- new /obj/item/weapon/paper/nuke_instructions(src)
-
-/obj/item/weapon/storage/box/syndie_kit/tuberculosisgrenade
- name = "boxed virus grenade kit"
-
-/obj/item/weapon/storage/box/syndie_kit/tuberculosisgrenade/PopulateContents()
- new /obj/item/weapon/grenade/chem_grenade/tuberculosis(src)
- for(var/i in 1 to 5)
- new /obj/item/weapon/reagent_containers/hypospray/medipen/tuberculosiscure(src)
- new /obj/item/weapon/reagent_containers/syringe(src)
- new /obj/item/weapon/reagent_containers/glass/bottle/tuberculosiscure(src)
-
-/obj/item/weapon/storage/box/syndie_kit/chameleon
- name = "chameleon kit"
-
-/obj/item/weapon/storage/box/syndie_kit/chameleon/PopulateContents()
- new /obj/item/clothing/under/chameleon(src)
- new /obj/item/clothing/suit/chameleon(src)
- new /obj/item/clothing/gloves/chameleon(src)
- new /obj/item/clothing/shoes/chameleon(src)
- new /obj/item/clothing/glasses/chameleon(src)
- new /obj/item/clothing/head/chameleon(src)
- new /obj/item/clothing/mask/chameleon(src)
- new /obj/item/weapon/storage/backpack/chameleon(src)
- new /obj/item/device/radio/headset/chameleon(src)
- new /obj/item/weapon/stamp/chameleon(src)
- new /obj/item/device/pda/chameleon(src)
- new /obj/item/weapon/gun/energy/laser/chameleon(src)
-
-//5*(2*4) = 5*8 = 45, 45 damage if you hit one person with all 5 stars.
-//Not counting the damage it will do while embedded (2*4 = 8, at 15% chance)
-/obj/item/weapon/storage/box/syndie_kit/throwing_weapons/PopulateContents()
- new /obj/item/weapon/throwing_star(src)
- new /obj/item/weapon/throwing_star(src)
- new /obj/item/weapon/throwing_star(src)
- new /obj/item/weapon/throwing_star(src)
- new /obj/item/weapon/throwing_star(src)
- new /obj/item/weapon/restraints/legcuffs/bola/tactical(src)
- new /obj/item/weapon/restraints/legcuffs/bola/tactical(src)
-
-/obj/item/weapon/storage/box/syndie_kit/cutouts/PopulateContents()
- for(var/i in 1 to 3)
- new/obj/item/cardboard_cutout/adaptive(src)
- new/obj/item/toy/crayon/rainbow(src)
-
-/obj/item/weapon/storage/box/syndie_kit/romerol/PopulateContents()
- new /obj/item/weapon/reagent_containers/glass/bottle/romerol(src)
- new /obj/item/weapon/reagent_containers/syringe(src)
- new /obj/item/weapon/reagent_containers/dropper(src)
-
-/obj/item/weapon/storage/box/syndie_kit/ez_clean/PopulateContents()
- for(var/i in 1 to 3)
- new/obj/item/weapon/grenade/chem_grenade/ez_clean(src)
-
-/obj/item/weapon/storage/box/hug/reverse_revolver/PopulateContents()
- new /obj/item/weapon/gun/ballistic/revolver/reverse(src)
-
-/obj/item/weapon/storage/box/syndie_kit/mimery/PopulateContents()
- new /obj/item/weapon/spellbook/oneuse/mimery_blockade(src)
- new /obj/item/weapon/spellbook/oneuse/mimery_guns(src)
-
-/obj/item/weapon/storage/box/syndie_kit/holoparasite
- name = "box"
-
-/obj/item/weapon/storage/box/syndie_kit/holoparasite/PopulateContents()
- new /obj/item/weapon/guardiancreator/tech/choose/traitor(src)
+/obj/item/weapon/storage/box/syndicate
+
+/obj/item/weapon/storage/box/syndicate/PopulateContents()
+ switch (pickweight(list("bloodyspai" = 3, "stealth" = 2, "bond" = 2, "screwed" = 2, "sabotage" = 3, "guns" = 2, "murder" = 2, "implant" = 1, "hacker" = 3, "darklord" = 1, "sniper" = 1, "metaops" = 1, "ninja" = 1)))
+ if("bloodyspai") // 27 tc now this is more right
+ new /obj/item/clothing/under/chameleon(src) // 2 tc since it's not the full set
+ new /obj/item/clothing/mask/chameleon(src) // Goes with above
+ new /obj/item/weapon/card/id/syndicate(src) // 2 tc
+ new /obj/item/clothing/shoes/chameleon(src) // 2 tc
+ new /obj/item/device/camera_bug(src) // 1 tc
+ new /obj/item/device/multitool/ai_detect(src) // 1 tc
+ new /obj/item/device/encryptionkey/syndicate(src) // 2 tc
+ new /obj/item/weapon/reagent_containers/syringe/mulligan(src) // 4 tc
+ new /obj/item/weapon/switchblade(src) //I'll count this as 2 tc
+ new /obj/item/weapon/storage/fancy/cigarettes/cigpack_syndicate (src) // 2 tc this shit heals
+ new /obj/item/device/flashlight/emp(src) // 2 tc
+ new /obj/item/device/chameleon(src) // 7 tc
+
+ if("stealth") // 31 tc
+ new /obj/item/weapon/gun/energy/kinetic_accelerator/crossbow(src)
+ new /obj/item/weapon/pen/sleepy(src)
+ new /obj/item/device/healthanalyzer/rad_laser(src)
+ new /obj/item/device/chameleon(src)
+ new /obj/item/weapon/soap/syndie(src)
+ new /obj/item/clothing/glasses/thermal/syndi(src)
+
+ if("bond") // 29 tc
+ new /obj/item/weapon/gun/ballistic/automatic/pistol(src)
+ new /obj/item/weapon/suppressor(src)
+ new /obj/item/ammo_box/magazine/m10mm(src)
+ new /obj/item/ammo_box/magazine/m10mm(src)
+ new /obj/item/clothing/under/chameleon(src)
+ new /obj/item/weapon/card/id/syndicate(src)
+ new /obj/item/weapon/reagent_containers/syringe/stimulants(src)
+
+ if("screwed") // 29 tc
+ new /obj/item/device/sbeacondrop/bomb(src)
+ new /obj/item/weapon/grenade/syndieminibomb(src)
+ new /obj/item/device/sbeacondrop/powersink(src)
+ new /obj/item/clothing/suit/space/syndicate/black/red(src)
+ new /obj/item/clothing/head/helmet/space/syndicate/black/red(src)
+ new /obj/item/device/encryptionkey/syndicate(src)
+
+ if("guns") // 28 tc now
+ new /obj/item/weapon/gun/ballistic/revolver(src)
+ new /obj/item/ammo_box/a357(src)
+ new /obj/item/ammo_box/a357(src)
+ new /obj/item/weapon/card/emag(src)
+ new /obj/item/weapon/grenade/plastic/c4(src)
+ new /obj/item/clothing/gloves/color/latex/nitrile(src)
+ new /obj/item/clothing/mask/gas/clown_hat(src)
+ new /obj/item/clothing/under/suit_jacket/really_black(src)
+
+ if("murder") // 28 tc now
+ new /obj/item/weapon/melee/energy/sword/saber(src)
+ new /obj/item/clothing/glasses/thermal/syndi(src)
+ new /obj/item/weapon/card/emag(src)
+ new /obj/item/clothing/shoes/chameleon(src)
+ new /obj/item/device/encryptionkey/syndicate(src)
+ new /obj/item/weapon/grenade/syndieminibomb(src)
+
+ if("implant") // 55+ tc holy shit what the fuck this is a lottery disguised as fun boxes isn't it?
+ new /obj/item/weapon/implanter/freedom(src)
+ new /obj/item/weapon/implanter/uplink/precharged(src)
+ new /obj/item/weapon/implanter/emp(src)
+ new /obj/item/weapon/implanter/adrenalin(src)
+ new /obj/item/weapon/implanter/explosive(src)
+ new /obj/item/weapon/implanter/storage(src)
+
+ if("hacker") // 26 tc
+ new /obj/item/weapon/aiModule/syndicate(src)
+ new /obj/item/weapon/card/emag(src)
+ new /obj/item/device/encryptionkey/binary(src)
+ new /obj/item/weapon/aiModule/toyAI(src)
+ new /obj/item/device/multitool/ai_detect(src)
+
+ if("lordsingulo") // 24 tc
+ new /obj/item/device/sbeacondrop(src)
+ new /obj/item/clothing/suit/space/syndicate/black/red(src)
+ new /obj/item/clothing/head/helmet/space/syndicate/black/red(src)
+ new /obj/item/weapon/card/emag(src)
+
+ if("sabotage") // 26 tc now
+ new /obj/item/weapon/grenade/plastic/c4 (src)
+ new /obj/item/weapon/grenade/plastic/c4 (src)
+ new /obj/item/device/doorCharge(src)
+ new /obj/item/device/doorCharge(src)
+ new /obj/item/device/camera_bug(src)
+ new /obj/item/device/sbeacondrop/powersink(src)
+ new /obj/item/weapon/cartridge/syndicate(src)
+ new /obj/item/weapon/storage/toolbox/syndicate(src) //To actually get to those places
+ new /obj/item/pizzabox/bomb
+
+ if("darklord") //20 tc + tk + summon item close enough for now
+ new /obj/item/weapon/twohanded/dualsaber(src)
+ new /obj/item/weapon/dnainjector/telemut/darkbundle(src)
+ new /obj/item/clothing/suit/hooded/chaplain_hoodie(src)
+ new /obj/item/weapon/card/id/syndicate(src)
+ new /obj/item/clothing/shoes/chameleon(src) //because slipping while being a dark lord sucks
+ new /obj/item/weapon/spellbook/oneuse/summonitem(src)
+
+ if("sniper") //This shit is unique so can't really balance it around tc, also no silencer because getting killed without ANY indicator on what killed you sucks
+ new /obj/item/weapon/gun/ballistic/automatic/sniper_rifle(src) // 12 tc
+ new /obj/item/ammo_box/magazine/sniper_rounds/penetrator(src)
+ new /obj/item/clothing/glasses/thermal/syndi(src)
+ new /obj/item/clothing/gloves/color/latex/nitrile(src)
+ new /obj/item/clothing/mask/gas/clown_hat(src)
+ new /obj/item/clothing/under/suit_jacket/really_black(src)
+
+ if("metaops") // 30 tc
+ new /obj/item/clothing/suit/space/hardsuit/syndi(src) // 8 tc
+ new /obj/item/weapon/gun/ballistic/automatic/shotgun/bulldog/unrestricted(src) // 8 tc
+ new /obj/item/weapon/implanter/explosive(src) // 2 tc
+ new /obj/item/ammo_box/magazine/m12g/buckshot(src) // 2 tc
+ new /obj/item/ammo_box/magazine/m12g/buckshot(src) // 2 tc
+ new /obj/item/weapon/grenade/plastic/c4 (src) // 1 tc
+ new /obj/item/weapon/grenade/plastic/c4 (src) // 1 tc
+ new /obj/item/weapon/card/emag(src) // 6 tc
+
+ if("ninja") // 33 tc worth
+ new /obj/item/weapon/katana(src) // Unique , hard to tell how much tc this is worth. 8 tc?
+ new /obj/item/weapon/implanter/adrenalin(src) // 8 tc
+ new /obj/item/weapon/throwing_star(src) // ~5 tc for all 6
+ new /obj/item/weapon/throwing_star(src)
+ new /obj/item/weapon/throwing_star(src)
+ new /obj/item/weapon/throwing_star(src)
+ new /obj/item/weapon/throwing_star(src)
+ new /obj/item/weapon/throwing_star(src)
+ new /obj/item/weapon/storage/belt/chameleon(src) // Unique but worth at least 2 tc
+ new /obj/item/weapon/card/id/syndicate(src) // 2 tc
+ new /obj/item/device/chameleon(src) // 7 tc
+
+/obj/item/weapon/storage/box/syndie_kit
+ name = "box"
+ desc = "A sleek, sturdy box."
+ icon_state = "syndiebox"
+ illustration = "writing_syndie"
+
+/obj/item/weapon/storage/box/syndie_kit/imp_freedom
+ name = "boxed freedom implant (with injector)"
+
+/obj/item/weapon/storage/box/syndie_kit/imp_freedom/PopulateContents()
+ var/obj/item/weapon/implanter/O = new(src)
+ O.imp = new /obj/item/weapon/implant/freedom(O)
+ O.update_icon()
+
+/obj/item/weapon/storage/box/syndie_kit/imp_microbomb
+ name = "Microbomb Implant (with injector)"
+
+/obj/item/weapon/storage/box/syndie_kit/imp_microbomb/PopulateContents()
+ var/obj/item/weapon/implanter/O = new(src)
+ O.imp = new /obj/item/weapon/implant/explosive(O)
+ O.update_icon()
+
+/obj/item/weapon/storage/box/syndie_kit/imp_macrobomb
+ name = "Macrobomb Implant (with injector)"
+
+/obj/item/weapon/storage/box/syndie_kit/imp_macrobomb/PopulateContents()
+ var/obj/item/weapon/implanter/O = new(src)
+ O.imp = new /obj/item/weapon/implant/explosive/macro(O)
+ O.update_icon()
+
+/obj/item/weapon/storage/box/syndie_kit/imp_uplink
+ name = "boxed uplink implant (with injector)"
+
+/obj/item/weapon/storage/box/syndie_kit/imp_uplink/PopulateContents()
+ ..()
+ var/obj/item/weapon/implanter/O = new(src)
+ O.imp = new /obj/item/weapon/implant/uplink(O)
+ O.update_icon()
+
+/obj/item/weapon/storage/box/syndie_kit/bioterror
+ name = "bioterror syringe box"
+
+/obj/item/weapon/storage/box/syndie_kit/bioterror/PopulateContents()
+ for(var/i in 1 to 7)
+ new /obj/item/weapon/reagent_containers/syringe/bioterror(src)
+
+/obj/item/weapon/storage/box/syndie_kit/imp_adrenal
+ name = "boxed adrenal implant (with injector)"
+
+/obj/item/weapon/storage/box/syndie_kit/imp_adrenal/PopulateContents()
+ var/obj/item/weapon/implanter/O = new(src)
+ O.imp = new /obj/item/weapon/implant/adrenalin(O)
+ O.update_icon()
+
+/obj/item/weapon/storage/box/syndie_kit/imp_storage
+ name = "boxed storage implant (with injector)"
+
+/obj/item/weapon/storage/box/syndie_kit/imp_storage/PopulateContents()
+ new /obj/item/weapon/implanter/storage(src)
+
+/obj/item/weapon/storage/box/syndie_kit/space
+ name = "boxed space suit and helmet"
+ can_hold = list(/obj/item/clothing/suit/space/syndicate, /obj/item/clothing/head/helmet/space/syndicate)
+ max_w_class = WEIGHT_CLASS_NORMAL
+
+/obj/item/weapon/storage/box/syndie_kit/space/PopulateContents()
+ new /obj/item/clothing/suit/space/syndicate/black/red(src) // Black and red is so in right now
+ new /obj/item/clothing/head/helmet/space/syndicate/black/red(src)
+
+/obj/item/weapon/storage/box/syndie_kit/emp
+ name = "boxed EMP kit"
+
+/obj/item/weapon/storage/box/syndie_kit/emp/PopulateContents()
+ new /obj/item/weapon/grenade/empgrenade(src)
+ new /obj/item/weapon/grenade/empgrenade(src)
+ new /obj/item/weapon/grenade/empgrenade(src)
+ new /obj/item/weapon/grenade/empgrenade(src)
+ new /obj/item/weapon/grenade/empgrenade(src)
+ new /obj/item/weapon/implanter/emp(src)
+
+/obj/item/weapon/storage/box/syndie_kit/chemical
+ name = "boxed chemical kit"
+ storage_slots = 14
+
+/obj/item/weapon/storage/box/syndie_kit/chemical/PopulateContents()
+ new /obj/item/weapon/reagent_containers/glass/bottle/polonium(src)
+ new /obj/item/weapon/reagent_containers/glass/bottle/venom(src)
+ new /obj/item/weapon/reagent_containers/glass/bottle/neurotoxin2(src)
+ new /obj/item/weapon/reagent_containers/glass/bottle/formaldehyde(src)
+ new /obj/item/weapon/reagent_containers/glass/bottle/spewium(src)
+ new /obj/item/weapon/reagent_containers/glass/bottle/cyanide(src)
+ new /obj/item/weapon/reagent_containers/glass/bottle/histamine(src)
+ new /obj/item/weapon/reagent_containers/glass/bottle/initropidril(src)
+ new /obj/item/weapon/reagent_containers/glass/bottle/pancuronium(src)
+ new /obj/item/weapon/reagent_containers/glass/bottle/sodium_thiopental(src)
+ new /obj/item/weapon/reagent_containers/glass/bottle/coniine(src)
+ new /obj/item/weapon/reagent_containers/glass/bottle/curare(src)
+ new /obj/item/weapon/reagent_containers/glass/bottle/amanitin(src)
+ new /obj/item/weapon/reagent_containers/syringe(src)
+
+/obj/item/weapon/storage/box/syndie_kit/nuke
+ name = "box"
+
+/obj/item/weapon/storage/box/syndie_kit/nuke/PopulateContents()
+ new /obj/item/weapon/screwdriver/nuke(src)
+ new /obj/item/nuke_core_container(src)
+ new /obj/item/weapon/paper/nuke_instructions(src)
+
+/obj/item/weapon/storage/box/syndie_kit/tuberculosisgrenade
+ name = "boxed virus grenade kit"
+
+/obj/item/weapon/storage/box/syndie_kit/tuberculosisgrenade/PopulateContents()
+ new /obj/item/weapon/grenade/chem_grenade/tuberculosis(src)
+ for(var/i in 1 to 5)
+ new /obj/item/weapon/reagent_containers/hypospray/medipen/tuberculosiscure(src)
+ new /obj/item/weapon/reagent_containers/syringe(src)
+ new /obj/item/weapon/reagent_containers/glass/bottle/tuberculosiscure(src)
+
+/obj/item/weapon/storage/box/syndie_kit/chameleon
+ name = "chameleon kit"
+
+/obj/item/weapon/storage/box/syndie_kit/chameleon/PopulateContents()
+ new /obj/item/clothing/under/chameleon(src)
+ new /obj/item/clothing/suit/chameleon(src)
+ new /obj/item/clothing/gloves/chameleon(src)
+ new /obj/item/clothing/shoes/chameleon(src)
+ new /obj/item/clothing/glasses/chameleon(src)
+ new /obj/item/clothing/head/chameleon(src)
+ new /obj/item/clothing/mask/chameleon(src)
+ new /obj/item/weapon/storage/backpack/chameleon(src)
+ new /obj/item/device/radio/headset/chameleon(src)
+ new /obj/item/weapon/stamp/chameleon(src)
+ new /obj/item/device/pda/chameleon(src)
+ new /obj/item/weapon/gun/energy/laser/chameleon(src)
+
+//5*(2*4) = 5*8 = 45, 45 damage if you hit one person with all 5 stars.
+//Not counting the damage it will do while embedded (2*4 = 8, at 15% chance)
+/obj/item/weapon/storage/box/syndie_kit/throwing_weapons/PopulateContents()
+ new /obj/item/weapon/throwing_star(src)
+ new /obj/item/weapon/throwing_star(src)
+ new /obj/item/weapon/throwing_star(src)
+ new /obj/item/weapon/throwing_star(src)
+ new /obj/item/weapon/throwing_star(src)
+ new /obj/item/weapon/restraints/legcuffs/bola/tactical(src)
+ new /obj/item/weapon/restraints/legcuffs/bola/tactical(src)
+
+/obj/item/weapon/storage/box/syndie_kit/cutouts/PopulateContents()
+ for(var/i in 1 to 3)
+ new/obj/item/cardboard_cutout/adaptive(src)
+ new/obj/item/toy/crayon/rainbow(src)
+
+/obj/item/weapon/storage/box/syndie_kit/romerol/PopulateContents()
+ new /obj/item/weapon/reagent_containers/glass/bottle/romerol(src)
+ new /obj/item/weapon/reagent_containers/syringe(src)
+ new /obj/item/weapon/reagent_containers/dropper(src)
+
+/obj/item/weapon/storage/box/syndie_kit/ez_clean/PopulateContents()
+ for(var/i in 1 to 3)
+ new/obj/item/weapon/grenade/chem_grenade/ez_clean(src)
+
+/obj/item/weapon/storage/box/hug/reverse_revolver/PopulateContents()
+ new /obj/item/weapon/gun/ballistic/revolver/reverse(src)
+
+/obj/item/weapon/storage/box/syndie_kit/mimery/PopulateContents()
+ new /obj/item/weapon/spellbook/oneuse/mimery_blockade(src)
+ new /obj/item/weapon/spellbook/oneuse/mimery_guns(src)
+
+/obj/item/weapon/storage/box/syndie_kit/holoparasite
+ name = "box"
+
+/obj/item/weapon/storage/box/syndie_kit/holoparasite/PopulateContents()
+ new /obj/item/weapon/guardiancreator/tech/choose/traitor(src)
new /obj/item/weapon/paper/guardian(src)
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/vending_items.dm b/code/game/objects/items/weapons/vending_items.dm
index b8a9314f54..5424e45044 100644
--- a/code/game/objects/items/weapons/vending_items.dm
+++ b/code/game/objects/items/weapons/vending_items.dm
@@ -1,79 +1,79 @@
-/obj/item/weapon/vending_refill
- name = "resupply canister"
- var/machine_name = "Generic"
-
- icon = 'icons/obj/vending_restock.dmi'
- icon_state = "refill_snack"
- item_state = "restock_unit"
- flags = CONDUCT
- force = 7
- throwforce = 10
- throw_speed = 1
- throw_range = 7
- w_class = WEIGHT_CLASS_BULKY
- armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 70, acid = 30)
- var/charges = list(0, 0, 0) //how many restocking "charges" the refill has for standard/contraband/coin products
- var/init_charges = list(0, 0, 0)
-
-
-/obj/item/weapon/vending_refill/New(amt = -1)
- ..()
- name = "\improper [machine_name] restocking unit"
- if(isnum(amt) && amt > -1)
- charges[1] = amt
-
-/obj/item/weapon/vending_refill/examine(mob/user)
- ..()
- if(charges[1] > 0)
- to_chat(user, "It can restock [charges[1]+charges[2]+charges[3]] item(s).")
- else
- to_chat(user, "It's empty!")
-
-//NOTE I decided to go for about 1/3 of a machine's capacity
-
-/obj/item/weapon/vending_refill/boozeomat
- machine_name = "Booze-O-Mat"
- icon_state = "refill_booze"
- charges = list(54, 4, 0)//of 159 standard, 12 contraband
- init_charges = list(54, 4, 0)
-
-/obj/item/weapon/vending_refill/coffee
- machine_name = "Solar's Best Hot Drinks"
- icon_state = "refill_joe"
- charges = list(25, 4, 0)//of 75 standard, 12 contraband
- init_charges = list(25, 4, 0)
-
-/obj/item/weapon/vending_refill/snack
- machine_name = "Getmore Chocolate Corp"
- charges = list(12, 2, 0)//of 36 standard, 6 contraband
- init_charges = list(12, 2, 0)
-
-/obj/item/weapon/vending_refill/cola
- machine_name = "Robust Softdrinks"
- icon_state = "refill_cola"
- charges = list(30, 4, 1)//of 90 standard, 12 contraband, 1 premium
- init_charges = list(30, 4, 1)
-
-/obj/item/weapon/vending_refill/cigarette
- machine_name = "ShadyCigs Deluxe"
- icon_state = "refill_smoke"
- charges = list(12, 3, 2)// of 36 standard, 9 contraband, 6 premium
- init_charges = list(12, 3, 2)
-
-/obj/item/weapon/vending_refill/autodrobe
- machine_name = "AutoDrobe"
- icon_state = "refill_costume"
- charges = list(31, 2, 3)// of 94 standard, 6 contraband, 9 premium
- init_charges = list(27, 2, 3)
-
-/obj/item/weapon/vending_refill/clothing
- machine_name = "ClothesMate"
- icon_state = "refill_clothes"
- charges = list(31, 4, 4)// of 101 standard, 12 contraband, 10 premium(?)
- init_charges = list(31, 4, 4)
-
-/obj/item/weapon/vending_refill/medical
- machine_name = "NanoMed"
- icon_state = "refill_medical"
- charges = list(26, 5, 3)// of 76 standard, 13 contraband, 8 premium
+/obj/item/weapon/vending_refill
+ name = "resupply canister"
+ var/machine_name = "Generic"
+
+ icon = 'icons/obj/vending_restock.dmi'
+ icon_state = "refill_snack"
+ item_state = "restock_unit"
+ flags = CONDUCT
+ force = 7
+ throwforce = 10
+ throw_speed = 1
+ throw_range = 7
+ w_class = WEIGHT_CLASS_BULKY
+ armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 70, acid = 30)
+ var/charges = list(0, 0, 0) //how many restocking "charges" the refill has for standard/contraband/coin products
+ var/init_charges = list(0, 0, 0)
+
+
+/obj/item/weapon/vending_refill/New(amt = -1)
+ ..()
+ name = "\improper [machine_name] restocking unit"
+ if(isnum(amt) && amt > -1)
+ charges[1] = amt
+
+/obj/item/weapon/vending_refill/examine(mob/user)
+ ..()
+ if(charges[1] > 0)
+ to_chat(user, "It can restock [charges[1]+charges[2]+charges[3]] item(s).")
+ else
+ to_chat(user, "It's empty!")
+
+//NOTE I decided to go for about 1/3 of a machine's capacity
+
+/obj/item/weapon/vending_refill/boozeomat
+ machine_name = "Booze-O-Mat"
+ icon_state = "refill_booze"
+ charges = list(54, 4, 0)//of 159 standard, 12 contraband
+ init_charges = list(54, 4, 0)
+
+/obj/item/weapon/vending_refill/coffee
+ machine_name = "Solar's Best Hot Drinks"
+ icon_state = "refill_joe"
+ charges = list(25, 4, 0)//of 75 standard, 12 contraband
+ init_charges = list(25, 4, 0)
+
+/obj/item/weapon/vending_refill/snack
+ machine_name = "Getmore Chocolate Corp"
+ charges = list(12, 2, 0)//of 36 standard, 6 contraband
+ init_charges = list(12, 2, 0)
+
+/obj/item/weapon/vending_refill/cola
+ machine_name = "Robust Softdrinks"
+ icon_state = "refill_cola"
+ charges = list(30, 4, 1)//of 90 standard, 12 contraband, 1 premium
+ init_charges = list(30, 4, 1)
+
+/obj/item/weapon/vending_refill/cigarette
+ machine_name = "ShadyCigs Deluxe"
+ icon_state = "refill_smoke"
+ charges = list(12, 3, 2)// of 36 standard, 9 contraband, 6 premium
+ init_charges = list(12, 3, 2)
+
+/obj/item/weapon/vending_refill/autodrobe
+ machine_name = "AutoDrobe"
+ icon_state = "refill_costume"
+ charges = list(31, 2, 3)// of 94 standard, 6 contraband, 9 premium
+ init_charges = list(27, 2, 3)
+
+/obj/item/weapon/vending_refill/clothing
+ machine_name = "ClothesMate"
+ icon_state = "refill_clothes"
+ charges = list(31, 4, 4)// of 101 standard, 12 contraband, 10 premium(?)
+ init_charges = list(31, 4, 4)
+
+/obj/item/weapon/vending_refill/medical
+ machine_name = "NanoMed"
+ icon_state = "refill_medical"
+ charges = list(26, 5, 3)// of 76 standard, 13 contraband, 8 premium
init_charges = list(26, 5, 3)
\ No newline at end of file
diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm
index 17aea280e0..43fbdde5ee 100644
--- a/code/game/objects/structures/displaycase.dm
+++ b/code/game/objects/structures/displaycase.dm
@@ -1,361 +1,361 @@
-/obj/structure/displaycase
- name = "display case"
- icon = 'icons/obj/stationobjs.dmi'
- icon_state = "glassbox0"
- desc = "A display case for prized possessions."
- density = 1
- anchored = 1
- resistance_flags = ACID_PROOF
- armor = list(melee = 30, bullet = 0, laser = 0, energy = 0, bomb = 10, bio = 0, rad = 0, fire = 70, acid = 100)
- obj_integrity = 200
- max_integrity = 200
- integrity_failure = 50
- var/obj/item/showpiece = null
- var/alert = TRUE
- var/open = FALSE
- var/openable = TRUE
- var/obj/item/weapon/electronics/airlock/electronics
- var/start_showpiece_type = null //add type for items on display
-
-/obj/structure/displaycase/Initialize()
- . = ..()
- if(start_showpiece_type)
- showpiece = new start_showpiece_type (src)
- update_icon()
-
-/obj/structure/displaycase/Destroy()
- if(electronics)
- QDEL_NULL(electronics)
- if(showpiece)
- QDEL_NULL(showpiece)
- return ..()
-
-/obj/structure/displaycase/examine(mob/user)
- ..()
- if(alert)
- to_chat(user, "Hooked up with an anti-theft system.")
- if(showpiece)
- to_chat(user, "There's [showpiece] inside.")
-
-
-/obj/structure/displaycase/proc/dump()
- if (showpiece)
- showpiece.forceMove(loc)
- showpiece = null
-
-/obj/structure/displaycase/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
- switch(damage_type)
- if(BRUTE)
- playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1)
- if(BURN)
- playsound(src.loc, 'sound/items/Welder.ogg', 100, 1)
-
-/obj/structure/displaycase/deconstruct(disassembled = TRUE)
- if(!(flags & NODECONSTRUCT))
- dump()
- if(!disassembled)
- new /obj/item/weapon/shard( src.loc )
- trigger_alarm()
- qdel(src)
-
-/obj/structure/displaycase/obj_break(damage_flag)
- if(!broken && !(flags & NODECONSTRUCT))
- density = 0
- broken = 1
- new /obj/item/weapon/shard( src.loc )
- playsound(src, "shatter", 70, 1)
- update_icon()
- trigger_alarm()
-
-/obj/structure/displaycase/proc/trigger_alarm()
- //Activate Anti-theft
- if(alert)
- var/area/alarmed = get_area(src)
- alarmed.burglaralert(src)
- playsound(src, 'sound/effects/alert.ogg', 50, 1)
-
-/*
-
-*/
-
-/obj/structure/displaycase/proc/is_directional(atom/A)
- try
- getFlatIcon(A,defdir=4)
- catch
- return FALSE
- return TRUE
-
-/obj/structure/displaycase/proc/get_flat_icon_directional(atom/A)
- //Get flatIcon even if dir is mismatched for directionless icons
- //SLOW
- var/icon/I
- if(is_directional(A))
- I = getFlatIcon(A)
- else
- var/old_dir = A.dir
- A.setDir(2)
- I = getFlatIcon(A)
- A.setDir(old_dir)
- return I
-
-/obj/structure/displaycase/update_icon()
- var/icon/I
- if(open)
- I = icon('icons/obj/stationobjs.dmi',"glassbox_open")
- else
- I = icon('icons/obj/stationobjs.dmi',"glassbox0")
- if(broken)
- I = icon('icons/obj/stationobjs.dmi',"glassboxb0")
- if(showpiece)
- var/icon/S = get_flat_icon_directional(showpiece)
- S.Scale(17,17)
- I.Blend(S,ICON_UNDERLAY,8,8)
- src.icon = I
- return
-
-/obj/structure/displaycase/attackby(obj/item/weapon/W, mob/user, params)
- if(W.GetID() && !broken && openable)
- if(allowed(user))
- to_chat(user, "You [open ? "close":"open"] the [src]")
- toggle_lock(user)
- else
- to_chat(user, "Access denied.")
- else if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent == INTENT_HELP && !broken)
- var/obj/item/weapon/weldingtool/WT = W
- if(obj_integrity < max_integrity && WT.remove_fuel(5, user))
- to_chat(user, "You begin repairing [src].")
- playsound(loc, WT.usesound, 40, 1)
- if(do_after(user, 40*W.toolspeed, target = src))
- obj_integrity = max_integrity
- playsound(loc, 'sound/items/Welder2.ogg', 50, 1)
- update_icon()
- to_chat(user, "You repair [src].")
- else
- to_chat(user, "[src] is already in good condition!")
- return
- else if(!alert && istype(W,/obj/item/weapon/crowbar) && openable) //Only applies to the lab cage and player made display cases
- if(broken)
- if(showpiece)
- to_chat(user, "Remove the displayed object first.")
- else
- to_chat(user, "You remove the destroyed case")
- qdel(src)
- else
- to_chat(user, "You start to [open ? "close":"open"] the [src]")
- if(do_after(user, 20*W.toolspeed, target = src))
- to_chat(user, "You [open ? "close":"open"] the [src]")
- toggle_lock(user)
- else if(open && !showpiece)
- if(user.transferItemToLoc(W, src))
- showpiece = W
- to_chat(user, "You put [W] on display")
- update_icon()
- else if(istype(W, /obj/item/stack/sheet/glass) && broken)
- var/obj/item/stack/sheet/glass/G = W
- if(G.get_amount() < 2)
- to_chat(user, "You need two glass sheets to fix the case!")
- return
- to_chat(user, "You start fixing [src]...")
- if(do_after(user, 20, target = src))
- G.use(2)
- broken = 0
- obj_integrity = max_integrity
- update_icon()
- else
- return ..()
-
-/obj/structure/displaycase/proc/toggle_lock(mob/user)
- open = !open
- update_icon()
-
-/obj/structure/displaycase/attack_paw(mob/user)
- return src.attack_hand(user)
-
-/obj/structure/displaycase/attack_hand(mob/user)
- user.changeNext_move(CLICK_CD_MELEE)
- if (showpiece && (broken || open))
- to_chat(user, "You deactivate the hover field built into the case.")
- dump()
- src.add_fingerprint(user)
- update_icon()
- return
- else
- //prevents remote "kicks" with TK
- if (!Adjacent(user))
- return
- user.visible_message("[user] kicks the display case.", null, null, COMBAT_MESSAGE_RANGE)
- user.do_attack_animation(src, ATTACK_EFFECT_KICK)
- take_damage(2)
-
-
-
-/obj/structure/displaycase_chassis
- anchored = 1
- density = 0
- name = "display case chassis"
- desc = "wooden base of display case"
- icon = 'icons/obj/stationobjs.dmi'
- icon_state = "glassbox_chassis"
- var/obj/item/weapon/electronics/airlock/electronics
-
-
-/obj/structure/displaycase_chassis/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/weapon/wrench)) //The player can only deconstruct the wooden frame
- to_chat(user, "You start disassembling [src]...")
- playsound(src.loc, I.usesound, 50, 1)
- if(do_after(user, 30*I.toolspeed, target = src))
- playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
- new /obj/item/stack/sheet/mineral/wood(get_turf(src), 5)
- qdel(src)
-
- else if(istype(I, /obj/item/weapon/electronics/airlock))
- to_chat(user, "You start installing the electronics into [src]...")
- playsound(src.loc, I.usesound, 50, 1)
- if(do_after(user, 30, target = src) && user.transferItemToLoc(I,src))
- electronics = I
- to_chat(user, "You install the airlock electronics.")
-
- else if(istype(I, /obj/item/stack/sheet/glass))
- var/obj/item/stack/sheet/glass/G = I
- if(G.get_amount() < 10)
- to_chat(user, "You need ten glass sheets to do this!")
- return
- to_chat(user, "You start adding [G] to [src]...")
- if(do_after(user, 20, target = src))
- G.use(10)
- var/obj/structure/displaycase/display = new(src.loc)
- if(electronics)
- electronics.loc = display
- display.electronics = electronics
- if(electronics.one_access)
- display.req_one_access = electronics.accesses
- else
- display.req_access = electronics.accesses
- qdel(src)
- else
- return ..()
-
-//The captains display case requiring specops ID access is intentional.
-//The lab cage and captains display case do not spawn with electronics, which is why req_access is needed.
-/obj/structure/displaycase/captain
- alert = 1
- start_showpiece_type = /obj/item/weapon/gun/energy/laser/captain
- req_access = list(GLOB.access_cent_specops)
-
-/obj/structure/displaycase/labcage
- name = "lab cage"
- desc = "A glass lab container for storing interesting creatures."
- start_showpiece_type = /obj/item/clothing/mask/facehugger/lamarr
- req_access = list(GLOB.access_rd)
-
-/obj/structure/displaycase/trophy
- name = "trophy display case"
- desc = "Store your trophies of accomplishment in here, and they will stay forever."
- var/trophy_message = ""
- var/placer_key = ""
- var/added_roundstart = TRUE
- var/is_locked = TRUE
-
- alert = TRUE
- integrity_failure = 0
- openable = FALSE
-
-/obj/structure/displaycase/trophy/Initialize()
- . = ..()
- GLOB.trophy_cases += src
-
-/obj/structure/displaycase/trophy/Destroy()
- GLOB.trophy_cases -= src
- return ..()
-
-/obj/structure/displaycase/trophy/examine(mob/user)
- ..()
- if(trophy_message)
- to_chat(user, "The plaque reads:")
- to_chat(user, trophy_message)
-
-/obj/structure/displaycase/trophy/attackby(obj/item/weapon/W, mob/user, params)
-
- if(!user.Adjacent(src)) //no TK museology
- return
- if(user.a_intent == INTENT_HARM)
- return ..()
-
- if(user.is_holding_item_of_type(/obj/item/key/displaycase))
- if(added_roundstart)
- is_locked = !is_locked
- to_chat(user, "You [!is_locked ? "un" : ""]lock the case.")
- else
- to_chat(user, "The lock is stuck shut!")
- return
-
- if(is_locked)
- to_chat(user, "The case is shut tight with an old fashioned physical lock. Maybe you should ask the curator for the key?")
- return
-
- if(!added_roundstart)
- to_chat(user, "You've already put something new in this case.")
- return
-
- if(is_type_in_typecache(W, GLOB.blacklisted_cargo_types))
- to_chat(user, "The case rejects the [W].")
- return
-
- for(var/a in W.GetAllContents())
- if(is_type_in_typecache(a, GLOB.blacklisted_cargo_types))
- to_chat(user, "The case rejects the [W].")
- return
-
- if(user.transferItemToLoc(W, src))
-
- if(showpiece)
- to_chat(user, "You press a button, and [showpiece] descends into the floor of the case.")
- QDEL_NULL(showpiece)
-
- to_chat(user, "You insert [W] into the case.")
- showpiece = W
- added_roundstart = FALSE
- update_icon()
-
- placer_key = user.ckey
-
- trophy_message = W.desc //default value
-
- var/chosen_plaque = stripped_input(user, "What would you like the plaque to say? Default value is item's description.", "Trophy Plaque")
- if(chosen_plaque)
- if(user.Adjacent(src))
- trophy_message = chosen_plaque
- to_chat(user, "You set the plaque's text.")
- else
- to_chat(user, "You are too far to set the plaque's text.")
-
- SSpersistence.SaveTrophy(src)
- return TRUE
-
- else
- to_chat(user, "\The [W] is stuck to your hand, you can't put it in the [src.name]!")
-
- return
-
-/obj/structure/displaycase/trophy/dump()
- if (showpiece)
- if(added_roundstart)
- visible_message("The [showpiece] crumbles to dust!")
- new /obj/effect/decal/cleanable/ash(loc)
- QDEL_NULL(showpiece)
- else
- ..()
-
-/obj/item/key/displaycase
- name = "display case key"
- desc = "The key to the curator's display cases."
-
-/obj/item/showpiece_dummy
- name = "Cheap replica"
-
-/obj/item/showpiece_dummy/Initialize(mapload, path)
- . = ..()
- var/obj/item/I = path
- name = initial(I.name)
- icon = initial(I.icon)
- icon_state = initial(I.icon_state)
+/obj/structure/displaycase
+ name = "display case"
+ icon = 'icons/obj/stationobjs.dmi'
+ icon_state = "glassbox0"
+ desc = "A display case for prized possessions."
+ density = 1
+ anchored = 1
+ resistance_flags = ACID_PROOF
+ armor = list(melee = 30, bullet = 0, laser = 0, energy = 0, bomb = 10, bio = 0, rad = 0, fire = 70, acid = 100)
+ obj_integrity = 200
+ max_integrity = 200
+ integrity_failure = 50
+ var/obj/item/showpiece = null
+ var/alert = TRUE
+ var/open = FALSE
+ var/openable = TRUE
+ var/obj/item/weapon/electronics/airlock/electronics
+ var/start_showpiece_type = null //add type for items on display
+
+/obj/structure/displaycase/Initialize()
+ . = ..()
+ if(start_showpiece_type)
+ showpiece = new start_showpiece_type (src)
+ update_icon()
+
+/obj/structure/displaycase/Destroy()
+ if(electronics)
+ QDEL_NULL(electronics)
+ if(showpiece)
+ QDEL_NULL(showpiece)
+ return ..()
+
+/obj/structure/displaycase/examine(mob/user)
+ ..()
+ if(alert)
+ to_chat(user, "Hooked up with an anti-theft system.")
+ if(showpiece)
+ to_chat(user, "There's [showpiece] inside.")
+
+
+/obj/structure/displaycase/proc/dump()
+ if (showpiece)
+ showpiece.forceMove(loc)
+ showpiece = null
+
+/obj/structure/displaycase/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
+ switch(damage_type)
+ if(BRUTE)
+ playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1)
+ if(BURN)
+ playsound(src.loc, 'sound/items/Welder.ogg', 100, 1)
+
+/obj/structure/displaycase/deconstruct(disassembled = TRUE)
+ if(!(flags & NODECONSTRUCT))
+ dump()
+ if(!disassembled)
+ new /obj/item/weapon/shard( src.loc )
+ trigger_alarm()
+ qdel(src)
+
+/obj/structure/displaycase/obj_break(damage_flag)
+ if(!broken && !(flags & NODECONSTRUCT))
+ density = 0
+ broken = 1
+ new /obj/item/weapon/shard( src.loc )
+ playsound(src, "shatter", 70, 1)
+ update_icon()
+ trigger_alarm()
+
+/obj/structure/displaycase/proc/trigger_alarm()
+ //Activate Anti-theft
+ if(alert)
+ var/area/alarmed = get_area(src)
+ alarmed.burglaralert(src)
+ playsound(src, 'sound/effects/alert.ogg', 50, 1)
+
+/*
+
+*/
+
+/obj/structure/displaycase/proc/is_directional(atom/A)
+ try
+ getFlatIcon(A,defdir=4)
+ catch
+ return FALSE
+ return TRUE
+
+/obj/structure/displaycase/proc/get_flat_icon_directional(atom/A)
+ //Get flatIcon even if dir is mismatched for directionless icons
+ //SLOW
+ var/icon/I
+ if(is_directional(A))
+ I = getFlatIcon(A)
+ else
+ var/old_dir = A.dir
+ A.setDir(2)
+ I = getFlatIcon(A)
+ A.setDir(old_dir)
+ return I
+
+/obj/structure/displaycase/update_icon()
+ var/icon/I
+ if(open)
+ I = icon('icons/obj/stationobjs.dmi',"glassbox_open")
+ else
+ I = icon('icons/obj/stationobjs.dmi',"glassbox0")
+ if(broken)
+ I = icon('icons/obj/stationobjs.dmi',"glassboxb0")
+ if(showpiece)
+ var/icon/S = get_flat_icon_directional(showpiece)
+ S.Scale(17,17)
+ I.Blend(S,ICON_UNDERLAY,8,8)
+ src.icon = I
+ return
+
+/obj/structure/displaycase/attackby(obj/item/weapon/W, mob/user, params)
+ if(W.GetID() && !broken && openable)
+ if(allowed(user))
+ to_chat(user, "You [open ? "close":"open"] the [src]")
+ toggle_lock(user)
+ else
+ to_chat(user, "Access denied.")
+ else if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent == INTENT_HELP && !broken)
+ var/obj/item/weapon/weldingtool/WT = W
+ if(obj_integrity < max_integrity && WT.remove_fuel(5, user))
+ to_chat(user, "You begin repairing [src].")
+ playsound(loc, WT.usesound, 40, 1)
+ if(do_after(user, 40*W.toolspeed, target = src))
+ obj_integrity = max_integrity
+ playsound(loc, 'sound/items/Welder2.ogg', 50, 1)
+ update_icon()
+ to_chat(user, "You repair [src].")
+ else
+ to_chat(user, "[src] is already in good condition!")
+ return
+ else if(!alert && istype(W,/obj/item/weapon/crowbar) && openable) //Only applies to the lab cage and player made display cases
+ if(broken)
+ if(showpiece)
+ to_chat(user, "Remove the displayed object first.")
+ else
+ to_chat(user, "You remove the destroyed case")
+ qdel(src)
+ else
+ to_chat(user, "You start to [open ? "close":"open"] the [src]")
+ if(do_after(user, 20*W.toolspeed, target = src))
+ to_chat(user, "You [open ? "close":"open"] the [src]")
+ toggle_lock(user)
+ else if(open && !showpiece)
+ if(user.transferItemToLoc(W, src))
+ showpiece = W
+ to_chat(user, "You put [W] on display")
+ update_icon()
+ else if(istype(W, /obj/item/stack/sheet/glass) && broken)
+ var/obj/item/stack/sheet/glass/G = W
+ if(G.get_amount() < 2)
+ to_chat(user, "You need two glass sheets to fix the case!")
+ return
+ to_chat(user, "You start fixing [src]...")
+ if(do_after(user, 20, target = src))
+ G.use(2)
+ broken = 0
+ obj_integrity = max_integrity
+ update_icon()
+ else
+ return ..()
+
+/obj/structure/displaycase/proc/toggle_lock(mob/user)
+ open = !open
+ update_icon()
+
+/obj/structure/displaycase/attack_paw(mob/user)
+ return src.attack_hand(user)
+
+/obj/structure/displaycase/attack_hand(mob/user)
+ user.changeNext_move(CLICK_CD_MELEE)
+ if (showpiece && (broken || open))
+ to_chat(user, "You deactivate the hover field built into the case.")
+ dump()
+ src.add_fingerprint(user)
+ update_icon()
+ return
+ else
+ //prevents remote "kicks" with TK
+ if (!Adjacent(user))
+ return
+ user.visible_message("[user] kicks the display case.", null, null, COMBAT_MESSAGE_RANGE)
+ user.do_attack_animation(src, ATTACK_EFFECT_KICK)
+ take_damage(2)
+
+
+
+/obj/structure/displaycase_chassis
+ anchored = 1
+ density = 0
+ name = "display case chassis"
+ desc = "wooden base of display case"
+ icon = 'icons/obj/stationobjs.dmi'
+ icon_state = "glassbox_chassis"
+ var/obj/item/weapon/electronics/airlock/electronics
+
+
+/obj/structure/displaycase_chassis/attackby(obj/item/I, mob/user, params)
+ if(istype(I, /obj/item/weapon/wrench)) //The player can only deconstruct the wooden frame
+ to_chat(user, "You start disassembling [src]...")
+ playsound(src.loc, I.usesound, 50, 1)
+ if(do_after(user, 30*I.toolspeed, target = src))
+ playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
+ new /obj/item/stack/sheet/mineral/wood(get_turf(src), 5)
+ qdel(src)
+
+ else if(istype(I, /obj/item/weapon/electronics/airlock))
+ to_chat(user, "You start installing the electronics into [src]...")
+ playsound(src.loc, I.usesound, 50, 1)
+ if(do_after(user, 30, target = src) && user.transferItemToLoc(I,src))
+ electronics = I
+ to_chat(user, "You install the airlock electronics.")
+
+ else if(istype(I, /obj/item/stack/sheet/glass))
+ var/obj/item/stack/sheet/glass/G = I
+ if(G.get_amount() < 10)
+ to_chat(user, "You need ten glass sheets to do this!")
+ return
+ to_chat(user, "You start adding [G] to [src]...")
+ if(do_after(user, 20, target = src))
+ G.use(10)
+ var/obj/structure/displaycase/display = new(src.loc)
+ if(electronics)
+ electronics.loc = display
+ display.electronics = electronics
+ if(electronics.one_access)
+ display.req_one_access = electronics.accesses
+ else
+ display.req_access = electronics.accesses
+ qdel(src)
+ else
+ return ..()
+
+//The captains display case requiring specops ID access is intentional.
+//The lab cage and captains display case do not spawn with electronics, which is why req_access is needed.
+/obj/structure/displaycase/captain
+ alert = 1
+ start_showpiece_type = /obj/item/weapon/gun/energy/laser/captain
+ req_access = list(GLOB.access_cent_specops)
+
+/obj/structure/displaycase/labcage
+ name = "lab cage"
+ desc = "A glass lab container for storing interesting creatures."
+ start_showpiece_type = /obj/item/clothing/mask/facehugger/lamarr
+ req_access = list(GLOB.access_rd)
+
+/obj/structure/displaycase/trophy
+ name = "trophy display case"
+ desc = "Store your trophies of accomplishment in here, and they will stay forever."
+ var/trophy_message = ""
+ var/placer_key = ""
+ var/added_roundstart = TRUE
+ var/is_locked = TRUE
+
+ alert = TRUE
+ integrity_failure = 0
+ openable = FALSE
+
+/obj/structure/displaycase/trophy/Initialize()
+ . = ..()
+ GLOB.trophy_cases += src
+
+/obj/structure/displaycase/trophy/Destroy()
+ GLOB.trophy_cases -= src
+ return ..()
+
+/obj/structure/displaycase/trophy/examine(mob/user)
+ ..()
+ if(trophy_message)
+ to_chat(user, "The plaque reads:")
+ to_chat(user, trophy_message)
+
+/obj/structure/displaycase/trophy/attackby(obj/item/weapon/W, mob/user, params)
+
+ if(!user.Adjacent(src)) //no TK museology
+ return
+ if(user.a_intent == INTENT_HARM)
+ return ..()
+
+ if(user.is_holding_item_of_type(/obj/item/key/displaycase))
+ if(added_roundstart)
+ is_locked = !is_locked
+ to_chat(user, "You [!is_locked ? "un" : ""]lock the case.")
+ else
+ to_chat(user, "The lock is stuck shut!")
+ return
+
+ if(is_locked)
+ to_chat(user, "The case is shut tight with an old fashioned physical lock. Maybe you should ask the curator for the key?")
+ return
+
+ if(!added_roundstart)
+ to_chat(user, "You've already put something new in this case.")
+ return
+
+ if(is_type_in_typecache(W, GLOB.blacklisted_cargo_types))
+ to_chat(user, "The case rejects the [W].")
+ return
+
+ for(var/a in W.GetAllContents())
+ if(is_type_in_typecache(a, GLOB.blacklisted_cargo_types))
+ to_chat(user, "The case rejects the [W].")
+ return
+
+ if(user.transferItemToLoc(W, src))
+
+ if(showpiece)
+ to_chat(user, "You press a button, and [showpiece] descends into the floor of the case.")
+ QDEL_NULL(showpiece)
+
+ to_chat(user, "You insert [W] into the case.")
+ showpiece = W
+ added_roundstart = FALSE
+ update_icon()
+
+ placer_key = user.ckey
+
+ trophy_message = W.desc //default value
+
+ var/chosen_plaque = stripped_input(user, "What would you like the plaque to say? Default value is item's description.", "Trophy Plaque")
+ if(chosen_plaque)
+ if(user.Adjacent(src))
+ trophy_message = chosen_plaque
+ to_chat(user, "You set the plaque's text.")
+ else
+ to_chat(user, "You are too far to set the plaque's text.")
+
+ SSpersistence.SaveTrophy(src)
+ return TRUE
+
+ else
+ to_chat(user, "\The [W] is stuck to your hand, you can't put it in the [src.name]!")
+
+ return
+
+/obj/structure/displaycase/trophy/dump()
+ if (showpiece)
+ if(added_roundstart)
+ visible_message("The [showpiece] crumbles to dust!")
+ new /obj/effect/decal/cleanable/ash(loc)
+ QDEL_NULL(showpiece)
+ else
+ ..()
+
+/obj/item/key/displaycase
+ name = "display case key"
+ desc = "The key to the curator's display cases."
+
+/obj/item/showpiece_dummy
+ name = "Cheap replica"
+
+/obj/item/showpiece_dummy/Initialize(mapload, path)
+ . = ..()
+ var/obj/item/I = path
+ name = initial(I.name)
+ icon = initial(I.icon)
+ icon_state = initial(I.icon_state)
diff --git a/code/modules/awaymissions/gateway.dm b/code/modules/awaymissions/gateway.dm
index 1c8beb2e6d..a1cba47271 100644
--- a/code/modules/awaymissions/gateway.dm
+++ b/code/modules/awaymissions/gateway.dm
@@ -1,240 +1,240 @@
-GLOBAL_DATUM(the_gateway, /obj/machinery/gateway/centerstation)
-
-/obj/machinery/gateway
- name = "gateway"
- desc = "A mysterious gateway built by unknown hands, it allows for faster than light travel to far-flung locations."
- icon = 'icons/obj/machines/gateway.dmi'
- icon_state = "off"
- density = 1
- anchored = 1
- resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
- var/active = 0
- var/checkparts = TRUE
- var/list/obj/effect/landmark/randomspawns = list()
- var/calibrated = TRUE
- var/list/linked = list()
- var/can_link = FALSE //Is this the centerpiece?
-
-/obj/machinery/gateway/Initialize()
- randomspawns = GLOB.awaydestinations
- update_icon()
- if(!istype(src, /obj/machinery/gateway/centerstation) && !istype(src, /obj/machinery/gateway/centeraway))
- switch(dir)
- if(SOUTH,SOUTHEAST,SOUTHWEST)
- density = 0
- ..()
-
-/obj/machinery/gateway/proc/toggleoff()
- for(var/obj/machinery/gateway/G in linked)
- G.active = 0
- G.update_icon()
- active = 0
- update_icon()
-
-/obj/machinery/gateway/proc/detect()
- if(!can_link)
- return FALSE
- linked = list() //clear the list
- var/turf/T = loc
- var/ready = FALSE
-
- for(var/i in GLOB.alldirs)
- T = get_step(loc, i)
- var/obj/machinery/gateway/G = locate(/obj/machinery/gateway) in T
- if(G)
- linked.Add(G)
- continue
-
- //this is only done if we fail to find a part
- ready = FALSE
- toggleoff()
- break
-
- if((linked.len == 8) || !checkparts)
- ready = TRUE
- return ready
-
-/obj/machinery/gateway/update_icon()
- if(active)
- icon_state = "on"
- return
- icon_state = "off"
-
-//prevents shuttles attempting to rotate this since it messes up sprites
-/obj/machinery/gateway/shuttleRotate()
- return
-
-/obj/machinery/gateway/attack_hand(mob/user)
- if(!detect())
- return
- if(!active)
- toggleon(user)
- return
- toggleoff()
-
-/obj/machinery/gateway/proc/toggleon(mob/user)
- return FALSE
-
-/obj/machinery/gateway/centerstation/New()
- ..()
- if(!GLOB.the_gateway)
- GLOB.the_gateway = src
-
-/obj/machinery/gateway/centerstation/Destroy()
- if(GLOB.the_gateway == src)
- GLOB.the_gateway = null
- return ..()
-
-//this is da important part wot makes things go
-/obj/machinery/gateway/centerstation
- density = TRUE
- icon_state = "offcenter"
- use_power = TRUE
-
- //warping vars
- var/wait = 0 //this just grabs world.time at world start
- var/obj/machinery/gateway/centeraway/awaygate = null
- can_link = TRUE
-
-/obj/machinery/gateway/centerstation/Initialize()
- ..()
- update_icon()
- wait = world.time + config.gateway_delay //+ thirty minutes default
- awaygate = locate(/obj/machinery/gateway/centeraway)
-
-/obj/machinery/gateway/centerstation/update_icon()
- if(active)
- icon_state = "oncenter"
- return
- icon_state = "offcenter"
-
-/obj/machinery/gateway/centerstation/process()
- if((stat & (NOPOWER)) && use_power)
- if(active)
- toggleoff()
- return
-
- if(active)
- use_power(5000)
-
-/obj/machinery/gateway/centerstation/toggleon(mob/user)
- if(!detect())
- return
- if(!powered())
- return
- if(!awaygate)
- to_chat(user, "Error: No destination found.")
- return
- if(world.time < wait)
- to_chat(user, "Error: Warpspace triangulation in progress. Estimated time to completion: [round(((wait - world.time) / 10) / 60)] minutes.")
- return
-
- for(var/obj/machinery/gateway/G in linked)
- G.active = 1
- G.update_icon()
- active = 1
- update_icon()
-
-//okay, here's the good teleporting stuff
-/obj/machinery/gateway/centerstation/Bumped(atom/movable/AM)
- if(!active)
- return
- if(!detect())
- return
- if(!awaygate || QDELETED(awaygate))
- return
-
- if(awaygate.calibrated)
- AM.forceMove(get_step(awaygate.loc, SOUTH))
- AM.setDir(SOUTH)
- if (ismob(AM))
- var/mob/M = AM
- if (M.client)
- M.client.move_delay = max(world.time + 5, M.client.move_delay)
- return
- else
- var/obj/effect/landmark/dest = pick(randomspawns)
- if(dest)
- AM.forceMove(get_turf(dest))
- AM.setDir(SOUTH)
- use_power(5000)
- return
-
-/obj/machinery/gateway/centeraway/attackby(obj/item/device/W, mob/user, params)
- if(istype(W,/obj/item/device/multitool))
- if(calibrated)
- to_chat(user, "\black The gate is already calibrated, there is no work for you to do here.")
- return
- else
- to_chat(user, "Recalibration successful!: \black This gate's systems have been fine tuned. Travel to this gate will now be on target.")
- calibrated = TRUE
- return
-
-/////////////////////////////////////Away////////////////////////
-
-
-/obj/machinery/gateway/centeraway
- density = TRUE
- icon_state = "offcenter"
- use_power = FALSE
- var/obj/machinery/gateway/centeraway/stationgate = null
- can_link = TRUE
-
-
-/obj/machinery/gateway/centeraway/Initialize()
- ..()
- update_icon()
- stationgate = locate(/obj/machinery/gateway/centerstation)
-
-
-/obj/machinery/gateway/centeraway/update_icon()
- if(active)
- icon_state = "oncenter"
- return
- icon_state = "offcenter"
-
-/obj/machinery/gateway/centeraway/toggleon(mob/user)
- if(!detect())
- return
- if(!stationgate)
- to_chat(user, "Error: No destination found.")
- return
-
- for(var/obj/machinery/gateway/G in linked)
- G.active = 1
- G.update_icon()
- active = 1
- update_icon()
-
-/obj/machinery/gateway/centeraway/proc/check_exile_implant(mob/living/carbon/C)
- for(var/obj/item/weapon/implant/exile/E in C.implants)//Checking that there is an exile implant
- to_chat(C, "\black The station gate has detected your exile implant and is blocking your entry.")
- return TRUE
- return FALSE
-
-/obj/machinery/gateway/centeraway/Bumped(atom/movable/AM)
- if(!detect())
- return
- if(!active)
- return
- if(!stationgate || QDELETED(stationgate))
- return
- if(istype(AM, /mob/living/carbon))
- if(check_exile_implant(AM))
- return
- else
- for(var/mob/living/carbon/C in AM.contents)
- if(check_exile_implant(C))
- say("Rejecting [AM]: Exile implant detected in contained lifeform.")
- return
- if(AM.has_buckled_mobs())
- for(var/mob/living/carbon/C in AM.buckled_mobs)
- if(check_exile_implant(C))
- say("Rejecting [AM]: Exile implant detected in close proximity lifeform.")
- return
- AM.forceMove(get_step(stationgate.loc, SOUTH))
- AM.setDir(SOUTH)
- if (ismob(AM))
- var/mob/M = AM
- if (M.client)
- M.client.move_delay = max(world.time + 5, M.client.move_delay)
+GLOBAL_DATUM(the_gateway, /obj/machinery/gateway/centerstation)
+
+/obj/machinery/gateway
+ name = "gateway"
+ desc = "A mysterious gateway built by unknown hands, it allows for faster than light travel to far-flung locations."
+ icon = 'icons/obj/machines/gateway.dmi'
+ icon_state = "off"
+ density = 1
+ anchored = 1
+ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
+ var/active = 0
+ var/checkparts = TRUE
+ var/list/obj/effect/landmark/randomspawns = list()
+ var/calibrated = TRUE
+ var/list/linked = list()
+ var/can_link = FALSE //Is this the centerpiece?
+
+/obj/machinery/gateway/Initialize()
+ randomspawns = GLOB.awaydestinations
+ update_icon()
+ if(!istype(src, /obj/machinery/gateway/centerstation) && !istype(src, /obj/machinery/gateway/centeraway))
+ switch(dir)
+ if(SOUTH,SOUTHEAST,SOUTHWEST)
+ density = 0
+ ..()
+
+/obj/machinery/gateway/proc/toggleoff()
+ for(var/obj/machinery/gateway/G in linked)
+ G.active = 0
+ G.update_icon()
+ active = 0
+ update_icon()
+
+/obj/machinery/gateway/proc/detect()
+ if(!can_link)
+ return FALSE
+ linked = list() //clear the list
+ var/turf/T = loc
+ var/ready = FALSE
+
+ for(var/i in GLOB.alldirs)
+ T = get_step(loc, i)
+ var/obj/machinery/gateway/G = locate(/obj/machinery/gateway) in T
+ if(G)
+ linked.Add(G)
+ continue
+
+ //this is only done if we fail to find a part
+ ready = FALSE
+ toggleoff()
+ break
+
+ if((linked.len == 8) || !checkparts)
+ ready = TRUE
+ return ready
+
+/obj/machinery/gateway/update_icon()
+ if(active)
+ icon_state = "on"
+ return
+ icon_state = "off"
+
+//prevents shuttles attempting to rotate this since it messes up sprites
+/obj/machinery/gateway/shuttleRotate()
+ return
+
+/obj/machinery/gateway/attack_hand(mob/user)
+ if(!detect())
+ return
+ if(!active)
+ toggleon(user)
+ return
+ toggleoff()
+
+/obj/machinery/gateway/proc/toggleon(mob/user)
+ return FALSE
+
+/obj/machinery/gateway/centerstation/New()
+ ..()
+ if(!GLOB.the_gateway)
+ GLOB.the_gateway = src
+
+/obj/machinery/gateway/centerstation/Destroy()
+ if(GLOB.the_gateway == src)
+ GLOB.the_gateway = null
+ return ..()
+
+//this is da important part wot makes things go
+/obj/machinery/gateway/centerstation
+ density = TRUE
+ icon_state = "offcenter"
+ use_power = TRUE
+
+ //warping vars
+ var/wait = 0 //this just grabs world.time at world start
+ var/obj/machinery/gateway/centeraway/awaygate = null
+ can_link = TRUE
+
+/obj/machinery/gateway/centerstation/Initialize()
+ ..()
+ update_icon()
+ wait = world.time + config.gateway_delay //+ thirty minutes default
+ awaygate = locate(/obj/machinery/gateway/centeraway)
+
+/obj/machinery/gateway/centerstation/update_icon()
+ if(active)
+ icon_state = "oncenter"
+ return
+ icon_state = "offcenter"
+
+/obj/machinery/gateway/centerstation/process()
+ if((stat & (NOPOWER)) && use_power)
+ if(active)
+ toggleoff()
+ return
+
+ if(active)
+ use_power(5000)
+
+/obj/machinery/gateway/centerstation/toggleon(mob/user)
+ if(!detect())
+ return
+ if(!powered())
+ return
+ if(!awaygate)
+ to_chat(user, "Error: No destination found.")
+ return
+ if(world.time < wait)
+ to_chat(user, "Error: Warpspace triangulation in progress. Estimated time to completion: [round(((wait - world.time) / 10) / 60)] minutes.")
+ return
+
+ for(var/obj/machinery/gateway/G in linked)
+ G.active = 1
+ G.update_icon()
+ active = 1
+ update_icon()
+
+//okay, here's the good teleporting stuff
+/obj/machinery/gateway/centerstation/Bumped(atom/movable/AM)
+ if(!active)
+ return
+ if(!detect())
+ return
+ if(!awaygate || QDELETED(awaygate))
+ return
+
+ if(awaygate.calibrated)
+ AM.forceMove(get_step(awaygate.loc, SOUTH))
+ AM.setDir(SOUTH)
+ if (ismob(AM))
+ var/mob/M = AM
+ if (M.client)
+ M.client.move_delay = max(world.time + 5, M.client.move_delay)
+ return
+ else
+ var/obj/effect/landmark/dest = pick(randomspawns)
+ if(dest)
+ AM.forceMove(get_turf(dest))
+ AM.setDir(SOUTH)
+ use_power(5000)
+ return
+
+/obj/machinery/gateway/centeraway/attackby(obj/item/device/W, mob/user, params)
+ if(istype(W,/obj/item/device/multitool))
+ if(calibrated)
+ to_chat(user, "\black The gate is already calibrated, there is no work for you to do here.")
+ return
+ else
+ to_chat(user, "Recalibration successful!: \black This gate's systems have been fine tuned. Travel to this gate will now be on target.")
+ calibrated = TRUE
+ return
+
+/////////////////////////////////////Away////////////////////////
+
+
+/obj/machinery/gateway/centeraway
+ density = TRUE
+ icon_state = "offcenter"
+ use_power = FALSE
+ var/obj/machinery/gateway/centeraway/stationgate = null
+ can_link = TRUE
+
+
+/obj/machinery/gateway/centeraway/Initialize()
+ ..()
+ update_icon()
+ stationgate = locate(/obj/machinery/gateway/centerstation)
+
+
+/obj/machinery/gateway/centeraway/update_icon()
+ if(active)
+ icon_state = "oncenter"
+ return
+ icon_state = "offcenter"
+
+/obj/machinery/gateway/centeraway/toggleon(mob/user)
+ if(!detect())
+ return
+ if(!stationgate)
+ to_chat(user, "Error: No destination found.")
+ return
+
+ for(var/obj/machinery/gateway/G in linked)
+ G.active = 1
+ G.update_icon()
+ active = 1
+ update_icon()
+
+/obj/machinery/gateway/centeraway/proc/check_exile_implant(mob/living/carbon/C)
+ for(var/obj/item/weapon/implant/exile/E in C.implants)//Checking that there is an exile implant
+ to_chat(C, "\black The station gate has detected your exile implant and is blocking your entry.")
+ return TRUE
+ return FALSE
+
+/obj/machinery/gateway/centeraway/Bumped(atom/movable/AM)
+ if(!detect())
+ return
+ if(!active)
+ return
+ if(!stationgate || QDELETED(stationgate))
+ return
+ if(istype(AM, /mob/living/carbon))
+ if(check_exile_implant(AM))
+ return
+ else
+ for(var/mob/living/carbon/C in AM.contents)
+ if(check_exile_implant(C))
+ say("Rejecting [AM]: Exile implant detected in contained lifeform.")
+ return
+ if(AM.has_buckled_mobs())
+ for(var/mob/living/carbon/C in AM.buckled_mobs)
+ if(check_exile_implant(C))
+ say("Rejecting [AM]: Exile implant detected in close proximity lifeform.")
+ return
+ AM.forceMove(get_step(stationgate.loc, SOUTH))
+ AM.setDir(SOUTH)
+ if (ismob(AM))
+ var/mob/M = AM
+ if (M.client)
+ M.client.move_delay = max(world.time + 5, M.client.move_delay)
diff --git a/code/modules/clothing/head/collectable.dm b/code/modules/clothing/head/collectable.dm
index 67ce5b3131..8ec8d00c77 100644
--- a/code/modules/clothing/head/collectable.dm
+++ b/code/modules/clothing/head/collectable.dm
@@ -1,147 +1,147 @@
-
-//Hat Station 13
-
-/obj/item/clothing/head/collectable
- name = "collectable hat"
- desc = "A rare collectable hat."
-
-/obj/item/clothing/head/collectable/petehat
- name = "ultra rare Pete's hat!"
- desc = "It smells faintly of plasma."
- icon_state = "petehat"
-
-/obj/item/clothing/head/collectable/slime
- name = "collectable slime cap!"
- desc = "It just latches right in place!"
- icon_state = "slime"
-
-/obj/item/clothing/head/collectable/xenom
- name = "collectable xenomorph helmet!"
- desc = "Hiss hiss hiss!"
- icon_state = "xenom"
-
-/obj/item/clothing/head/collectable/chef
- name = "collectable chef's hat"
- desc = "A rare chef's hat meant for hat collectors!"
- icon_state = "chef"
- item_state = "chef"
-
- dog_fashion = /datum/dog_fashion/head/chef
-
-/obj/item/clothing/head/collectable/paper
- name = "collectable paper hat"
- desc = "What looks like an ordinary paper hat is actually a rare and valuable collector's edition paper hat. Keep away from water, fire, and Curators."
- icon_state = "paper"
-
- dog_fashion = /datum/dog_fashion/head
-
-/obj/item/clothing/head/collectable/tophat
- name = "collectable top hat"
- desc = "A top hat worn by only the most prestigious hat collectors."
- icon_state = "tophat"
- item_state = "that"
-
-/obj/item/clothing/head/collectable/captain
- name = "collectable captain's hat"
- desc = "A collectable hat that'll make you look just like a real comdom!"
- icon_state = "captain"
- item_state = "caphat"
-
- dog_fashion = /datum/dog_fashion/head/captain
-
-/obj/item/clothing/head/collectable/police
- name = "collectable police officer's hat"
- desc = "A collectable police officer's Hat. This hat emphasizes that you are THE LAW."
- icon_state = "policehelm"
-
- dog_fashion = /datum/dog_fashion/head/warden
-
-/obj/item/clothing/head/collectable/beret
- name = "collectable beret"
- desc = "A collectable red beret. It smells faintly of garlic."
- icon_state = "beret"
-
- dog_fashion = /datum/dog_fashion/head/beret
-
-/obj/item/clothing/head/collectable/welding
- name = "collectable welding helmet"
- desc = "A collectable welding helmet. Now with 80% less lead! Not for actual welding. Any welding done while wearing this helmet is done so at the owner's own risk!"
- icon_state = "welding"
- item_state = "welding"
- resistance_flags = 0
-
-/obj/item/clothing/head/collectable/slime
- name = "collectable slime hat"
- desc = "Just like a real brain slug!"
- icon_state = "headslime"
- item_state = "headslime"
-
-/obj/item/clothing/head/collectable/flatcap
- name = "collectable flat cap"
- desc = "A collectible farmer's flat cap!"
- icon_state = "flat_cap"
- item_state = "detective"
-
-/obj/item/clothing/head/collectable/pirate
- name = "collectable pirate hat"
- desc = "You'd make a great Dread Syndie Roberts!"
- icon_state = "pirate"
- item_state = "pirate"
-
- dog_fashion = /datum/dog_fashion/head/pirate
-
-/obj/item/clothing/head/collectable/kitty
- name = "collectable kitty ears"
- desc = "The fur feels... a bit too realistic."
- icon_state = "kitty"
- item_state = "kitty"
-
- dog_fashion = /datum/dog_fashion/head/kitty
-
-/obj/item/clothing/head/collectable/rabbitears
- name = "collectable rabbit ears"
- desc = "Not as lucky as the feet!"
- icon_state = "bunny"
- item_state = "bunny"
-
- dog_fashion = /datum/dog_fashion/head/rabbit
-
-/obj/item/clothing/head/collectable/wizard
- name = "collectable wizard's hat"
- desc = "NOTE: Any magical powers gained from wearing this hat are purely coincidental."
- icon_state = "wizard"
-
- dog_fashion = /datum/dog_fashion/head/blue_wizard
-
-/obj/item/clothing/head/collectable/hardhat
- name = "collectable hard hat"
- desc = "WARNING! Offers no real protection, or luminosity, but damn, is it fancy!"
- icon_state = "hardhat0_yellow"
- item_state = "hardhat0_yellow"
-
- dog_fashion = /datum/dog_fashion/head
-
-/obj/item/clothing/head/collectable/HoS
- name = "collectable HoS hat"
- desc = "Now you too can beat prisoners, set silly sentences, and arrest for no reason!"
- icon_state = "hoscap"
-
-/obj/item/clothing/head/collectable/HoP
- name = "collectable HoP hat"
- desc = "It's your turn to demand excessive paperwork, signatures, stamps, and hire more clowns! Papers, please!"
- icon_state = "hopcap"
- dog_fashion = /datum/dog_fashion/head/hop
-
-/obj/item/clothing/head/collectable/thunderdome
- name = "collectable Thunderdome helmet"
- desc = "Go Red! I mean Green! I mean Red! No Green!"
- icon_state = "thunderdome"
- item_state = "thunderdome"
- resistance_flags = 0
-
-/obj/item/clothing/head/collectable/swat
- name = "collectable SWAT helmet"
- desc = "That's not real blood. That's red paint." //Reference to the actual description
- icon_state = "swat"
- item_state = "swat"
- resistance_flags = 0
+
+//Hat Station 13
+
+/obj/item/clothing/head/collectable
+ name = "collectable hat"
+ desc = "A rare collectable hat."
+
+/obj/item/clothing/head/collectable/petehat
+ name = "ultra rare Pete's hat!"
+ desc = "It smells faintly of plasma."
+ icon_state = "petehat"
+
+/obj/item/clothing/head/collectable/slime
+ name = "collectable slime cap!"
+ desc = "It just latches right in place!"
+ icon_state = "slime"
+
+/obj/item/clothing/head/collectable/xenom
+ name = "collectable xenomorph helmet!"
+ desc = "Hiss hiss hiss!"
+ icon_state = "xenom"
+
+/obj/item/clothing/head/collectable/chef
+ name = "collectable chef's hat"
+ desc = "A rare chef's hat meant for hat collectors!"
+ icon_state = "chef"
+ item_state = "chef"
+
+ dog_fashion = /datum/dog_fashion/head/chef
+
+/obj/item/clothing/head/collectable/paper
+ name = "collectable paper hat"
+ desc = "What looks like an ordinary paper hat is actually a rare and valuable collector's edition paper hat. Keep away from water, fire, and Curators."
+ icon_state = "paper"
+
+ dog_fashion = /datum/dog_fashion/head
+
+/obj/item/clothing/head/collectable/tophat
+ name = "collectable top hat"
+ desc = "A top hat worn by only the most prestigious hat collectors."
+ icon_state = "tophat"
+ item_state = "that"
+
+/obj/item/clothing/head/collectable/captain
+ name = "collectable captain's hat"
+ desc = "A collectable hat that'll make you look just like a real comdom!"
+ icon_state = "captain"
+ item_state = "caphat"
+
+ dog_fashion = /datum/dog_fashion/head/captain
+
+/obj/item/clothing/head/collectable/police
+ name = "collectable police officer's hat"
+ desc = "A collectable police officer's Hat. This hat emphasizes that you are THE LAW."
+ icon_state = "policehelm"
+
+ dog_fashion = /datum/dog_fashion/head/warden
+
+/obj/item/clothing/head/collectable/beret
+ name = "collectable beret"
+ desc = "A collectable red beret. It smells faintly of garlic."
+ icon_state = "beret"
+
+ dog_fashion = /datum/dog_fashion/head/beret
+
+/obj/item/clothing/head/collectable/welding
+ name = "collectable welding helmet"
+ desc = "A collectable welding helmet. Now with 80% less lead! Not for actual welding. Any welding done while wearing this helmet is done so at the owner's own risk!"
+ icon_state = "welding"
+ item_state = "welding"
+ resistance_flags = 0
+
+/obj/item/clothing/head/collectable/slime
+ name = "collectable slime hat"
+ desc = "Just like a real brain slug!"
+ icon_state = "headslime"
+ item_state = "headslime"
+
+/obj/item/clothing/head/collectable/flatcap
+ name = "collectable flat cap"
+ desc = "A collectible farmer's flat cap!"
+ icon_state = "flat_cap"
+ item_state = "detective"
+
+/obj/item/clothing/head/collectable/pirate
+ name = "collectable pirate hat"
+ desc = "You'd make a great Dread Syndie Roberts!"
+ icon_state = "pirate"
+ item_state = "pirate"
+
+ dog_fashion = /datum/dog_fashion/head/pirate
+
+/obj/item/clothing/head/collectable/kitty
+ name = "collectable kitty ears"
+ desc = "The fur feels... a bit too realistic."
+ icon_state = "kitty"
+ item_state = "kitty"
+
+ dog_fashion = /datum/dog_fashion/head/kitty
+
+/obj/item/clothing/head/collectable/rabbitears
+ name = "collectable rabbit ears"
+ desc = "Not as lucky as the feet!"
+ icon_state = "bunny"
+ item_state = "bunny"
+
+ dog_fashion = /datum/dog_fashion/head/rabbit
+
+/obj/item/clothing/head/collectable/wizard
+ name = "collectable wizard's hat"
+ desc = "NOTE: Any magical powers gained from wearing this hat are purely coincidental."
+ icon_state = "wizard"
+
+ dog_fashion = /datum/dog_fashion/head/blue_wizard
+
+/obj/item/clothing/head/collectable/hardhat
+ name = "collectable hard hat"
+ desc = "WARNING! Offers no real protection, or luminosity, but damn, is it fancy!"
+ icon_state = "hardhat0_yellow"
+ item_state = "hardhat0_yellow"
+
+ dog_fashion = /datum/dog_fashion/head
+
+/obj/item/clothing/head/collectable/HoS
+ name = "collectable HoS hat"
+ desc = "Now you too can beat prisoners, set silly sentences, and arrest for no reason!"
+ icon_state = "hoscap"
+
+/obj/item/clothing/head/collectable/HoP
+ name = "collectable HoP hat"
+ desc = "It's your turn to demand excessive paperwork, signatures, stamps, and hire more clowns! Papers, please!"
+ icon_state = "hopcap"
+ dog_fashion = /datum/dog_fashion/head/hop
+
+/obj/item/clothing/head/collectable/thunderdome
+ name = "collectable Thunderdome helmet"
+ desc = "Go Red! I mean Green! I mean Red! No Green!"
+ icon_state = "thunderdome"
+ item_state = "thunderdome"
+ resistance_flags = 0
+
+/obj/item/clothing/head/collectable/swat
+ name = "collectable SWAT helmet"
+ desc = "That's not real blood. That's red paint." //Reference to the actual description
+ icon_state = "swat"
+ item_state = "swat"
+ resistance_flags = 0
diff --git a/code/modules/detectivework/scanner.dm b/code/modules/detectivework/scanner.dm
index 0fd86219bc..c3d58ee67d 100644
--- a/code/modules/detectivework/scanner.dm
+++ b/code/modules/detectivework/scanner.dm
@@ -1,172 +1,172 @@
-//CONTAINS: Detective's Scanner
-
-// TODO: Split everything into easy to manage procs.
-
-/obj/item/device/detective_scanner
- name = "forensic scanner"
- desc = "Used to remotely scan objects and biomass for DNA and fingerprints. Can print a report of the findings."
- icon_state = "forensicnew"
- w_class = WEIGHT_CLASS_SMALL
- item_state = "electronic"
- flags = CONDUCT | NOBLUDGEON
- slot_flags = SLOT_BELT
- var/scanning = 0
- var/list/log = list()
- origin_tech = "engineering=4;biotech=2;programming=5"
- var/range = 8
- var/view_check = TRUE
-
-/obj/item/device/detective_scanner/attack_self(mob/user)
- if(log.len && !scanning)
- scanning = 1
- to_chat(user, "Printing report, please wait...")
- addtimer(CALLBACK(src, .proc/PrintReport), 100)
- else
- to_chat(user, "The scanner has no logs or is in use.")
-
-/obj/item/device/detective_scanner/attack(mob/living/M, mob/user)
- return
-
-/obj/item/device/detective_scanner/proc/PrintReport()
- // Create our paper
- var/obj/item/weapon/paper/P = new(get_turf(src))
- P.name = "paper- 'Scanner Report'"
- P.info = "Scanner Report
"
- P.info += jointext(log, "
")
- P.info += "
Notes:
"
- P.info_links = P.info
-
- if(ismob(loc))
- var/mob/M = loc
- M.put_in_hands(P)
- to_chat(M, "Report printed. Log cleared.")
-
- // Clear the logs
- log = list()
- scanning = 0
-
-/obj/item/device/detective_scanner/afterattack(atom/A, mob/user, params)
- scan(A, user)
- return FALSE
-
-/obj/item/device/detective_scanner/proc/scan(atom/A, mob/user)
- set waitfor = 0
- if(!scanning)
- // Can remotely scan objects and mobs.
- if((get_dist(A, user) > range) || (!(A in view(range, user)) && view_check) || (loc != user))
- return
-
- scanning = 1
-
- user.visible_message("\The [user] points the [src.name] at \the [A] and performs a forensic scan.")
- to_chat(user, "You scan \the [A]. The scanner is now analysing the results...")
-
-
- // GATHER INFORMATION
-
- //Make our lists
- var/list/fingerprints = list()
- var/list/blood = list()
- var/list/fibers = list()
- var/list/reagents = list()
-
- var/target_name = A.name
-
- // Start gathering
-
- if(A.blood_DNA && A.blood_DNA.len)
- blood = A.blood_DNA.Copy()
-
- if(A.suit_fibers && A.suit_fibers.len)
- fibers = A.suit_fibers.Copy()
-
- if(ishuman(A))
-
- var/mob/living/carbon/human/H = A
- if(!H.gloves)
- fingerprints += md5(H.dna.uni_identity)
-
- else if(!ismob(A))
-
- if(A.fingerprints && A.fingerprints.len)
- fingerprints = A.fingerprints.Copy()
-
- // Only get reagents from non-mobs.
- if(A.reagents && A.reagents.reagent_list.len)
-
- for(var/datum/reagent/R in A.reagents.reagent_list)
- reagents[R.name] = R.volume
-
- // Get blood data from the blood reagent.
- if(istype(R, /datum/reagent/blood))
-
- if(R.data["blood_DNA"] && R.data["blood_type"])
- var/blood_DNA = R.data["blood_DNA"]
- var/blood_type = R.data["blood_type"]
- blood[blood_DNA] = blood_type
-
- // We gathered everything. Create a fork and slowly display the results to the holder of the scanner.
-
- var/found_something = 0
- add_log("[worldtime2text()][get_timestamp()] - [target_name]", 0)
-
- // Fingerprints
- if(fingerprints && fingerprints.len)
- sleep(30)
- add_log("Prints:")
- for(var/finger in fingerprints)
- add_log("[finger]")
- found_something = 1
-
- // Blood
- if (blood && blood.len)
- sleep(30)
- add_log("Blood:")
- found_something = 1
- for(var/B in blood)
- add_log("Type: [blood[B]] DNA: [B]")
-
- //Fibers
- if(fibers && fibers.len)
- sleep(30)
- add_log("Fibers:")
- for(var/fiber in fibers)
- add_log("[fiber]")
- found_something = 1
-
- //Reagents
- if(reagents && reagents.len)
- sleep(30)
- add_log("Reagents:")
- for(var/R in reagents)
- add_log("Reagent: [R] Volume: [reagents[R]]")
- found_something = 1
-
- // Get a new user
- var/mob/holder = null
- if(ismob(src.loc))
- holder = src.loc
-
- if(!found_something)
- add_log("# No forensic traces found #", 0) // Don't display this to the holder user
- if(holder)
- to_chat(holder, "Unable to locate any fingerprints, materials, fibers, or blood on \the [target_name]!")
- else
- if(holder)
- to_chat(holder, "You finish scanning \the [target_name].")
-
- add_log("---------------------------------------------------------", 0)
- scanning = 0
- return
-
-/obj/item/device/detective_scanner/proc/add_log(msg, broadcast = 1)
- if(scanning)
- if(broadcast && ismob(loc))
- var/mob/M = loc
- to_chat(M, msg)
- log += " [msg]"
- else
- CRASH("[src] \ref[src] is adding a log when it was never put in scanning mode!")
-
-/proc/get_timestamp()
- return time2text(world.time + 432000, ":ss")
+//CONTAINS: Detective's Scanner
+
+// TODO: Split everything into easy to manage procs.
+
+/obj/item/device/detective_scanner
+ name = "forensic scanner"
+ desc = "Used to remotely scan objects and biomass for DNA and fingerprints. Can print a report of the findings."
+ icon_state = "forensicnew"
+ w_class = WEIGHT_CLASS_SMALL
+ item_state = "electronic"
+ flags = CONDUCT | NOBLUDGEON
+ slot_flags = SLOT_BELT
+ var/scanning = 0
+ var/list/log = list()
+ origin_tech = "engineering=4;biotech=2;programming=5"
+ var/range = 8
+ var/view_check = TRUE
+
+/obj/item/device/detective_scanner/attack_self(mob/user)
+ if(log.len && !scanning)
+ scanning = 1
+ to_chat(user, "Printing report, please wait...")
+ addtimer(CALLBACK(src, .proc/PrintReport), 100)
+ else
+ to_chat(user, "The scanner has no logs or is in use.")
+
+/obj/item/device/detective_scanner/attack(mob/living/M, mob/user)
+ return
+
+/obj/item/device/detective_scanner/proc/PrintReport()
+ // Create our paper
+ var/obj/item/weapon/paper/P = new(get_turf(src))
+ P.name = "paper- 'Scanner Report'"
+ P.info = "Scanner Report
"
+ P.info += jointext(log, "
")
+ P.info += "
Notes:
"
+ P.info_links = P.info
+
+ if(ismob(loc))
+ var/mob/M = loc
+ M.put_in_hands(P)
+ to_chat(M, "Report printed. Log cleared.")
+
+ // Clear the logs
+ log = list()
+ scanning = 0
+
+/obj/item/device/detective_scanner/afterattack(atom/A, mob/user, params)
+ scan(A, user)
+ return FALSE
+
+/obj/item/device/detective_scanner/proc/scan(atom/A, mob/user)
+ set waitfor = 0
+ if(!scanning)
+ // Can remotely scan objects and mobs.
+ if((get_dist(A, user) > range) || (!(A in view(range, user)) && view_check) || (loc != user))
+ return
+
+ scanning = 1
+
+ user.visible_message("\The [user] points the [src.name] at \the [A] and performs a forensic scan.")
+ to_chat(user, "You scan \the [A]. The scanner is now analysing the results...")
+
+
+ // GATHER INFORMATION
+
+ //Make our lists
+ var/list/fingerprints = list()
+ var/list/blood = list()
+ var/list/fibers = list()
+ var/list/reagents = list()
+
+ var/target_name = A.name
+
+ // Start gathering
+
+ if(A.blood_DNA && A.blood_DNA.len)
+ blood = A.blood_DNA.Copy()
+
+ if(A.suit_fibers && A.suit_fibers.len)
+ fibers = A.suit_fibers.Copy()
+
+ if(ishuman(A))
+
+ var/mob/living/carbon/human/H = A
+ if(!H.gloves)
+ fingerprints += md5(H.dna.uni_identity)
+
+ else if(!ismob(A))
+
+ if(A.fingerprints && A.fingerprints.len)
+ fingerprints = A.fingerprints.Copy()
+
+ // Only get reagents from non-mobs.
+ if(A.reagents && A.reagents.reagent_list.len)
+
+ for(var/datum/reagent/R in A.reagents.reagent_list)
+ reagents[R.name] = R.volume
+
+ // Get blood data from the blood reagent.
+ if(istype(R, /datum/reagent/blood))
+
+ if(R.data["blood_DNA"] && R.data["blood_type"])
+ var/blood_DNA = R.data["blood_DNA"]
+ var/blood_type = R.data["blood_type"]
+ blood[blood_DNA] = blood_type
+
+ // We gathered everything. Create a fork and slowly display the results to the holder of the scanner.
+
+ var/found_something = 0
+ add_log("[worldtime2text()][get_timestamp()] - [target_name]", 0)
+
+ // Fingerprints
+ if(fingerprints && fingerprints.len)
+ sleep(30)
+ add_log("Prints:")
+ for(var/finger in fingerprints)
+ add_log("[finger]")
+ found_something = 1
+
+ // Blood
+ if (blood && blood.len)
+ sleep(30)
+ add_log("Blood:")
+ found_something = 1
+ for(var/B in blood)
+ add_log("Type: [blood[B]] DNA: [B]")
+
+ //Fibers
+ if(fibers && fibers.len)
+ sleep(30)
+ add_log("Fibers:")
+ for(var/fiber in fibers)
+ add_log("[fiber]")
+ found_something = 1
+
+ //Reagents
+ if(reagents && reagents.len)
+ sleep(30)
+ add_log("Reagents:")
+ for(var/R in reagents)
+ add_log("Reagent: [R] Volume: [reagents[R]]")
+ found_something = 1
+
+ // Get a new user
+ var/mob/holder = null
+ if(ismob(src.loc))
+ holder = src.loc
+
+ if(!found_something)
+ add_log("# No forensic traces found #", 0) // Don't display this to the holder user
+ if(holder)
+ to_chat(holder, "Unable to locate any fingerprints, materials, fibers, or blood on \the [target_name]!")
+ else
+ if(holder)
+ to_chat(holder, "You finish scanning \the [target_name].")
+
+ add_log("---------------------------------------------------------", 0)
+ scanning = 0
+ return
+
+/obj/item/device/detective_scanner/proc/add_log(msg, broadcast = 1)
+ if(scanning)
+ if(broadcast && ismob(loc))
+ var/mob/M = loc
+ to_chat(M, msg)
+ log += " [msg]"
+ else
+ CRASH("[src] \ref[src] is adding a log when it was never put in scanning mode!")
+
+/proc/get_timestamp()
+ return time2text(world.time + 432000, ":ss")
diff --git a/code/modules/jobs/access.dm b/code/modules/jobs/access.dm
index 53126152ab..d3a8c089d6 100644
--- a/code/modules/jobs/access.dm
+++ b/code/modules/jobs/access.dm
@@ -1,481 +1,481 @@
-
-
-GLOBAL_VAR_CONST(access_security, 1) // Security equipment
-GLOBAL_VAR_CONST(access_brig, 2) // Brig timers and permabrig
-GLOBAL_VAR_CONST(access_armory, 3)
-GLOBAL_VAR_CONST(access_forensics_lockers, 4)
-GLOBAL_VAR_CONST(access_medical, 5)
-GLOBAL_VAR_CONST(access_morgue, 6)
-GLOBAL_VAR_CONST(access_tox, 7)
-GLOBAL_VAR_CONST(access_tox_storage, 8)
-GLOBAL_VAR_CONST(access_genetics, 9)
-GLOBAL_VAR_CONST(access_engine, 10)
-GLOBAL_VAR_CONST(access_engine_equip, 11)
-GLOBAL_VAR_CONST(access_maint_tunnels, 12)
-GLOBAL_VAR_CONST(access_external_airlocks, 13)
-GLOBAL_VAR_CONST(access_emergency_storage, 14)
-GLOBAL_VAR_CONST(access_change_ids, 15)
-GLOBAL_VAR_CONST(access_ai_upload, 16)
-GLOBAL_VAR_CONST(access_teleporter, 17)
-GLOBAL_VAR_CONST(access_eva, 18)
-GLOBAL_VAR_CONST(access_heads, 19)
-GLOBAL_VAR_CONST(access_captain, 20)
-GLOBAL_VAR_CONST(access_all_personal_lockers, 21)
-GLOBAL_VAR_CONST(access_chapel_office, 22)
-GLOBAL_VAR_CONST(access_tech_storage, 23)
-GLOBAL_VAR_CONST(access_atmospherics, 24)
-GLOBAL_VAR_CONST(access_bar, 25)
-GLOBAL_VAR_CONST(access_janitor, 26)
-GLOBAL_VAR_CONST(access_crematorium, 27)
-GLOBAL_VAR_CONST(access_kitchen, 28)
-GLOBAL_VAR_CONST(access_robotics, 29)
-GLOBAL_VAR_CONST(access_rd, 30)
-GLOBAL_VAR_CONST(access_cargo, 31)
-GLOBAL_VAR_CONST(access_construction, 32)
-GLOBAL_VAR_CONST(access_chemistry, 33)
-GLOBAL_VAR_CONST(access_cargo_bot, 34)
-GLOBAL_VAR_CONST(access_hydroponics, 35)
-GLOBAL_VAR_CONST(access_manufacturing, 36)
-GLOBAL_VAR_CONST(access_library, 37)
-GLOBAL_VAR_CONST(access_lawyer, 38)
-GLOBAL_VAR_CONST(access_virology, 39)
-GLOBAL_VAR_CONST(access_cmo, 40)
-GLOBAL_VAR_CONST(access_qm, 41)
-GLOBAL_VAR_CONST(access_court, 42)
-GLOBAL_VAR_CONST(access_surgery, 45)
-GLOBAL_VAR_CONST(access_theatre, 46)
-GLOBAL_VAR_CONST(access_research, 47)
-GLOBAL_VAR_CONST(access_mining, 48)
-GLOBAL_VAR_CONST(access_mining_office, 49) //not in use
-GLOBAL_VAR_CONST(access_mailsorting, 50)
-GLOBAL_VAR_CONST(access_mint, 51)
-GLOBAL_VAR_CONST(access_mint_vault, 52)
-GLOBAL_VAR_CONST(access_heads_vault, 53)
-GLOBAL_VAR_CONST(access_mining_station, 54)
-GLOBAL_VAR_CONST(access_xenobiology, 55)
-GLOBAL_VAR_CONST(access_ce, 56)
-GLOBAL_VAR_CONST(access_hop, 57)
-GLOBAL_VAR_CONST(access_hos, 58)
-GLOBAL_VAR_CONST(access_RC_announce, 59) //Request console announcements
-GLOBAL_VAR_CONST(access_keycard_auth, 60) //Used for events which require at least two people to confirm them
-GLOBAL_VAR_CONST(access_tcomsat, 61) // has access to the entire telecomms satellite / machinery
-GLOBAL_VAR_CONST(access_gateway, 62)
-GLOBAL_VAR_CONST(access_sec_doors, 63) // Security front doors
-GLOBAL_VAR_CONST(access_mineral_storeroom, 64)
-GLOBAL_VAR_CONST(access_minisat, 65)
-GLOBAL_VAR_CONST(access_weapons, 66) //Weapon authorization for secbots
-GLOBAL_VAR_CONST(access_network, 67)
-GLOBAL_VAR_CONST(access_cloning, 68) //Cloning room
-
- //BEGIN CENTCOM ACCESS
- /*Should leave plenty of room if we need to add more access levels.
- Mostly for admin fun times.*/
-GLOBAL_VAR_CONST(access_cent_general, 101)//General facilities.
-GLOBAL_VAR_CONST(access_cent_thunder, 102)//Thunderdome.
-GLOBAL_VAR_CONST(access_cent_specops, 103)//Special Ops.
-GLOBAL_VAR_CONST(access_cent_medical, 104)//Medical/Research
-GLOBAL_VAR_CONST(access_cent_living, 105)//Living quarters.
-GLOBAL_VAR_CONST(access_cent_storage, 106)//Generic storage areas.
-GLOBAL_VAR_CONST(access_cent_teleporter, 107)//Teleporter.
-GLOBAL_VAR_CONST(access_cent_captain, 109)//Captain's office/ID comp/AI.
-GLOBAL_VAR_CONST(access_cent_bar, 110) // The non-existent Centcom Bar
-
- //The Syndicate
-GLOBAL_VAR_CONST(access_syndicate, 150)//General Syndicate Access
-GLOBAL_VAR_CONST(access_syndicate_leader, 151)//Nuke Op Leader Access
-
- //Away Missions or Ruins
- /*For generic away-mission/ruin access. Why would normal crew have access to a long-abandoned derelict
- or a 2000 year-old temple? */
-GLOBAL_VAR_CONST(access_away_general, 200)//General facilities.
-GLOBAL_VAR_CONST(access_away_maint, 201)//Away maintenance
-GLOBAL_VAR_CONST(access_away_med, 202)//Away medical
-GLOBAL_VAR_CONST(access_away_sec, 203)//Away security
-GLOBAL_VAR_CONST(access_away_engine, 204)//Away engineering
-GLOBAL_VAR_CONST(access_away_generic1, 205)//Away generic access
-GLOBAL_VAR_CONST(access_away_generic2, 206)
-GLOBAL_VAR_CONST(access_away_generic3, 207)
-GLOBAL_VAR_CONST(access_away_generic4, 208)
-
-/obj/var/list/req_access = null
-/obj/var/req_access_txt = "0"
-/obj/var/list/req_one_access = null
-/obj/var/req_one_access_txt = "0"
-
-//returns 1 if this mob has sufficient access to use this object
-/obj/proc/allowed(mob/M)
- //check if it doesn't require any access at all
- if(src.check_access(null))
- return TRUE
- if(issilicon(M))
- if(ispAI(M))
- return FALSE
- return TRUE //AI can do whatever it wants
- if(IsAdminGhost(M))
- //Access can't stop the abuse
- return TRUE
- else if(ishuman(M))
- var/mob/living/carbon/human/H = M
- //if they are holding or wearing a card that has access, that works
- if(check_access(H.get_active_held_item()) || src.check_access(H.wear_id))
- return TRUE
- else if(ismonkey(M) || isalienadult(M))
- var/mob/living/carbon/george = M
- //they can only hold things :(
- if(check_access(george.get_active_held_item()))
- return TRUE
- else if(isanimal(M))
- var/mob/living/simple_animal/A = M
- if(check_access(A.get_active_held_item()) || check_access(A.access_card))
- return TRUE
- return FALSE
-
-/obj/item/proc/GetAccess()
- return list()
-
-/obj/item/proc/GetID()
- return null
-
-//Call this before using req_access or req_one_access directly
-/obj/proc/gen_access()
- //These generations have been moved out of /obj/New() because they were slowing down the creation of objects that never even used the access system.
- if(!src.req_access)
- src.req_access = list()
- if(src.req_access_txt)
- var/list/req_access_str = splittext(req_access_txt,";")
- for(var/x in req_access_str)
- var/n = text2num(x)
- if(n)
- req_access += n
-
- if(!src.req_one_access)
- src.req_one_access = list()
- if(src.req_one_access_txt)
- var/list/req_one_access_str = splittext(req_one_access_txt,";")
- for(var/x in req_one_access_str)
- var/n = text2num(x)
- if(n)
- req_one_access += n
-
-/obj/proc/check_access(obj/item/I)
- gen_access()
-
- if(!istype(src.req_access, /list)) //something's very wrong
- return TRUE
-
- var/list/L = src.req_access
- if(!L.len && (!src.req_one_access || !src.req_one_access.len)) //no requirements
- return TRUE
- if(!I)
- return FALSE
- for(var/req in src.req_access)
- if(!(req in I.GetAccess())) //doesn't have this access
- return FALSE
- if(src.req_one_access && src.req_one_access.len)
- for(var/req in src.req_one_access)
- if(req in I.GetAccess()) //has an access from the single access list
- return TRUE
- return FALSE
- return TRUE
-
-
-/obj/proc/check_access_list(list/L)
- if(!src.req_access && !src.req_one_access)
- return TRUE
- if(!istype(src.req_access, /list))
- return TRUE
- if(!src.req_access.len && (!src.req_one_access || !src.req_one_access.len))
- return TRUE
- if(!L)
- return FALSE
- if(!istype(L, /list))
- return FALSE
- for(var/req in src.req_access)
- if(!(req in L)) //doesn't have this access
- return FALSE
- if(src.req_one_access && src.req_one_access.len)
- for(var/req in src.req_one_access)
- if(req in L) //has an access from the single access list
- return TRUE
- return FALSE
- return TRUE
-
-/proc/get_centcom_access(job)
- switch(job)
- if("VIP Guest")
- return list(GLOB.access_cent_general)
- if("Custodian")
- return list(GLOB.access_cent_general, GLOB.access_cent_living, GLOB.access_cent_storage)
- if("Thunderdome Overseer")
- return list(GLOB.access_cent_general, GLOB.access_cent_thunder)
- if("Centcom Official")
- return list(GLOB.access_cent_general, GLOB.access_cent_living)
- if("Medical Officer")
- return list(GLOB.access_cent_general, GLOB.access_cent_living, GLOB.access_cent_medical)
- if("Death Commando")
- return list(GLOB.access_cent_general, GLOB.access_cent_specops, GLOB.access_cent_living, GLOB.access_cent_storage)
- if("Research Officer")
- return list(GLOB.access_cent_general, GLOB.access_cent_specops, GLOB.access_cent_medical, GLOB.access_cent_teleporter, GLOB.access_cent_storage)
- if("Special Ops Officer")
- return list(GLOB.access_cent_general, GLOB.access_cent_thunder, GLOB.access_cent_specops, GLOB.access_cent_living, GLOB.access_cent_storage)
- if("Admiral")
- return get_all_centcom_access()
- if("Centcom Commander")
- return get_all_centcom_access()
- if("Emergency Response Team Commander")
- return get_ert_access("commander")
- if("Security Response Officer")
- return get_ert_access("sec")
- if("Engineer Response Officer")
- return get_ert_access("eng")
- if("Medical Response Officer")
- return get_ert_access("med")
- if("Centcom Bartender")
- return list(GLOB.access_cent_general, GLOB.access_cent_living, GLOB.access_cent_bar)
-
-/proc/get_all_accesses()
- return list(GLOB.access_security, GLOB.access_sec_doors, GLOB.access_brig, GLOB.access_armory, GLOB.access_forensics_lockers, GLOB.access_court,
- GLOB.access_medical, GLOB.access_genetics, GLOB.access_morgue, GLOB.access_rd,
- GLOB.access_tox, GLOB.access_tox_storage, GLOB.access_chemistry, GLOB.access_engine, GLOB.access_engine_equip, GLOB.access_maint_tunnels,
- GLOB.access_external_airlocks, GLOB.access_change_ids, GLOB.access_ai_upload,
- GLOB.access_teleporter, GLOB.access_eva, GLOB.access_heads, GLOB.access_captain, GLOB.access_all_personal_lockers,
- GLOB.access_tech_storage, GLOB.access_chapel_office, GLOB.access_atmospherics, GLOB.access_kitchen,
- GLOB.access_bar, GLOB.access_janitor, GLOB.access_crematorium, GLOB.access_robotics, GLOB.access_cargo, GLOB.access_construction,
- GLOB.access_hydroponics, GLOB.access_library, GLOB.access_lawyer, GLOB.access_virology, GLOB.access_cmo, GLOB.access_qm, GLOB.access_surgery,
- GLOB.access_theatre, GLOB.access_research, GLOB.access_mining, GLOB.access_mailsorting, GLOB.access_weapons,
- GLOB.access_heads_vault, GLOB.access_mining_station, GLOB.access_xenobiology, GLOB.access_ce, GLOB.access_hop, GLOB.access_hos, GLOB.access_RC_announce,
- GLOB.access_keycard_auth, GLOB.access_tcomsat, GLOB.access_gateway, GLOB.access_mineral_storeroom, GLOB.access_minisat, GLOB.access_network, GLOB.access_cloning)
-
-/proc/get_all_centcom_access()
- return list(GLOB.access_cent_general, GLOB.access_cent_thunder, GLOB.access_cent_specops, GLOB.access_cent_medical, GLOB.access_cent_living, GLOB.access_cent_storage, GLOB.access_cent_teleporter, GLOB.access_cent_captain)
-
-/proc/get_ert_access(class)
- switch(class)
- if("commander")
- return get_all_centcom_access()
- if("sec")
- return list(GLOB.access_cent_general, GLOB.access_cent_specops, GLOB.access_cent_living)
- if("eng")
- return list(GLOB.access_cent_general, GLOB.access_cent_specops, GLOB.access_cent_living, GLOB.access_cent_storage)
- if("med")
- return list(GLOB.access_cent_general, GLOB.access_cent_specops, GLOB.access_cent_medical, GLOB.access_cent_living)
-
-/proc/get_all_syndicate_access()
- return list(GLOB.access_syndicate, GLOB.access_syndicate)
-
-/proc/get_region_accesses(code)
- switch(code)
- if(0)
- return get_all_accesses()
- if(1) //station general
- return list(GLOB.access_kitchen,GLOB.access_bar, GLOB.access_hydroponics, GLOB.access_janitor, GLOB.access_chapel_office, GLOB.access_crematorium, GLOB.access_library, GLOB.access_theatre, GLOB.access_lawyer)
- if(2) //security
- return list(GLOB.access_sec_doors, GLOB.access_weapons, GLOB.access_security, GLOB.access_brig, GLOB.access_armory, GLOB.access_forensics_lockers, GLOB.access_court, GLOB.access_hos)
- if(3) //medbay
- return list(GLOB.access_medical, GLOB.access_genetics, GLOB.access_cloning, GLOB.access_morgue, GLOB.access_chemistry, GLOB.access_virology, GLOB.access_surgery, GLOB.access_cmo)
- if(4) //research
- return list(GLOB.access_research, GLOB.access_tox, GLOB.access_tox_storage, GLOB.access_genetics, GLOB.access_robotics, GLOB.access_xenobiology, GLOB.access_minisat, GLOB.access_rd, GLOB.access_network)
- if(5) //engineering and maintenance
- return list(GLOB.access_construction, GLOB.access_maint_tunnels, GLOB.access_engine, GLOB.access_engine_equip, GLOB.access_external_airlocks, GLOB.access_tech_storage, GLOB.access_atmospherics, GLOB.access_tcomsat, GLOB.access_minisat, GLOB.access_ce)
- if(6) //supply
- return list(GLOB.access_mailsorting, GLOB.access_mining, GLOB.access_mining_station, GLOB.access_mineral_storeroom, GLOB.access_cargo, GLOB.access_qm)
- if(7) //command
- return list(GLOB.access_heads, GLOB.access_RC_announce, GLOB.access_keycard_auth, GLOB.access_change_ids, GLOB.access_ai_upload, GLOB.access_teleporter, GLOB.access_eva, GLOB.access_gateway, GLOB.access_all_personal_lockers, GLOB.access_heads_vault, GLOB.access_hop, GLOB.access_captain)
-
-/proc/get_region_accesses_name(code)
- switch(code)
- if(0)
- return "All"
- if(1) //station general
- return "General"
- if(2) //security
- return "Security"
- if(3) //medbay
- return "Medbay"
- if(4) //research
- return "Research"
- if(5) //engineering and maintenance
- return "Engineering"
- if(6) //supply
- return "Supply"
- if(7) //command
- return "Command"
-
-/proc/get_access_desc(A)
- switch(A)
- if(GLOB.access_cargo)
- return "Cargo Bay"
- if(GLOB.access_cargo_bot)
- return "Delivery Chutes"
- if(GLOB.access_security)
- return "Security"
- if(GLOB.access_brig)
- return "Holding Cells"
- if(GLOB.access_court)
- return "Courtroom"
- if(GLOB.access_forensics_lockers)
- return "Forensics"
- if(GLOB.access_medical)
- return "Medical"
- if(GLOB.access_genetics)
- return "Genetics Lab"
- if(GLOB.access_morgue)
- return "Morgue"
- if(GLOB.access_tox)
- return "R&D Lab"
- if(GLOB.access_tox_storage)
- return "Toxins Lab"
- if(GLOB.access_chemistry)
- return "Chemistry Lab"
- if(GLOB.access_rd)
- return "RD Office"
- if(GLOB.access_bar)
- return "Bar"
- if(GLOB.access_janitor)
- return "Custodial Closet"
- if(GLOB.access_engine)
- return "Engineering"
- if(GLOB.access_engine_equip)
- return "Power Equipment"
- if(GLOB.access_maint_tunnels)
- return "Maintenance"
- if(GLOB.access_external_airlocks)
- return "External Airlocks"
- if(GLOB.access_emergency_storage)
- return "Emergency Storage"
- if(GLOB.access_change_ids)
- return "ID Console"
- if(GLOB.access_ai_upload)
- return "AI Chambers"
- if(GLOB.access_teleporter)
- return "Teleporter"
- if(GLOB.access_eva)
- return "EVA"
- if(GLOB.access_heads)
- return "Bridge"
- if(GLOB.access_captain)
- return "Captain"
- if(GLOB.access_all_personal_lockers)
- return "Personal Lockers"
- if(GLOB.access_chapel_office)
- return "Chapel Office"
- if(GLOB.access_tech_storage)
- return "Technical Storage"
- if(GLOB.access_atmospherics)
- return "Atmospherics"
- if(GLOB.access_crematorium)
- return "Crematorium"
- if(GLOB.access_armory)
- return "Armory"
- if(GLOB.access_construction)
- return "Construction"
- if(GLOB.access_kitchen)
- return "Kitchen"
- if(GLOB.access_hydroponics)
- return "Hydroponics"
- if(GLOB.access_library)
- return "Library"
- if(GLOB.access_lawyer)
- return "Law Office"
- if(GLOB.access_robotics)
- return "Robotics"
- if(GLOB.access_virology)
- return "Virology"
- if(GLOB.access_cmo)
- return "CMO Office"
- if(GLOB.access_qm)
- return "Quartermaster"
- if(GLOB.access_surgery)
- return "Surgery"
- if(GLOB.access_theatre)
- return "Theatre"
- if(GLOB.access_manufacturing)
- return "Manufacturing"
- if(GLOB.access_research)
- return "Science"
- if(GLOB.access_mining)
- return "Mining"
- if(GLOB.access_mining_office)
- return "Mining Office"
- if(GLOB.access_mailsorting)
- return "Cargo Office"
- if(GLOB.access_mint)
- return "Mint"
- if(GLOB.access_mint_vault)
- return "Mint Vault"
- if(GLOB.access_heads_vault)
- return "Main Vault"
- if(GLOB.access_mining_station)
- return "Mining EVA"
- if(GLOB.access_xenobiology)
- return "Xenobiology Lab"
- if(GLOB.access_hop)
- return "HoP Office"
- if(GLOB.access_hos)
- return "HoS Office"
- if(GLOB.access_ce)
- return "CE Office"
- if(GLOB.access_RC_announce)
- return "RC Announcements"
- if(GLOB.access_keycard_auth)
- return "Keycode Auth."
- if(GLOB.access_tcomsat)
- return "Telecommunications"
- if(GLOB.access_gateway)
- return "Gateway"
- if(GLOB.access_sec_doors)
- return "Brig"
- if(GLOB.access_mineral_storeroom)
- return "Mineral Storage"
- if(GLOB.access_minisat)
- return "AI Satellite"
- if(GLOB.access_weapons)
- return "Weapon Permit"
- if(GLOB.access_network)
- return "Network Access"
- if(GLOB.access_cloning)
- return "Cloning Room"
-
-/proc/get_centcom_access_desc(A)
- switch(A)
- if(GLOB.access_cent_general)
- return "Code Grey"
- if(GLOB.access_cent_thunder)
- return "Code Yellow"
- if(GLOB.access_cent_storage)
- return "Code Orange"
- if(GLOB.access_cent_living)
- return "Code Green"
- if(GLOB.access_cent_medical)
- return "Code White"
- if(GLOB.access_cent_teleporter)
- return "Code Blue"
- if(GLOB.access_cent_specops)
- return "Code Black"
- if(GLOB.access_cent_captain)
- return "Code Gold"
- if(GLOB.access_cent_bar)
- return "Code Scotch"
-
-/proc/get_all_jobs()
- return list("Assistant", "Captain", "Head of Personnel", "Bartender", "Cook", "Botanist", "Quartermaster", "Cargo Technician",
- "Shaft Miner", "Clown", "Mime", "Janitor", "Curator", "Lawyer", "Chaplain", "Chief Engineer", "Station Engineer",
- "Atmospheric Technician", "Chief Medical Officer", "Medical Doctor", "Chemist", "Geneticist", "Virologist",
- "Research Director", "Scientist", "Roboticist", "Head of Security", "Warden", "Detective", "Security Officer")
-
-/proc/get_all_job_icons() //For all existing HUD icons
- return get_all_jobs() + list("Prisoner")
-
-/proc/get_all_centcom_jobs()
- return list("VIP Guest","Custodian","Thunderdome Overseer","Centcom Official","Medical Officer","Death Commando","Research Officer","Special Ops Officer","Admiral","Centcom Commander","Emergency Response Team Commander","Security Response Officer","Engineer Response Officer", "Medical Response Officer","Centcom Bartender")
-
-/obj/item/proc/GetJobName() //Used in secHUD icon generation
- var/obj/item/weapon/card/id/I = GetID()
- if(!I)
- return
- var/jobName = I.assignment
- if(jobName in get_all_job_icons()) //Check if the job has a hud icon
- return jobName
- if(jobName in get_all_centcom_jobs()) //Return with the NT logo if it is a Centcom job
- return "Centcom"
- return "Unknown" //Return unknown if none of the above apply
+
+
+GLOBAL_VAR_CONST(access_security, 1) // Security equipment
+GLOBAL_VAR_CONST(access_brig, 2) // Brig timers and permabrig
+GLOBAL_VAR_CONST(access_armory, 3)
+GLOBAL_VAR_CONST(access_forensics_lockers, 4)
+GLOBAL_VAR_CONST(access_medical, 5)
+GLOBAL_VAR_CONST(access_morgue, 6)
+GLOBAL_VAR_CONST(access_tox, 7)
+GLOBAL_VAR_CONST(access_tox_storage, 8)
+GLOBAL_VAR_CONST(access_genetics, 9)
+GLOBAL_VAR_CONST(access_engine, 10)
+GLOBAL_VAR_CONST(access_engine_equip, 11)
+GLOBAL_VAR_CONST(access_maint_tunnels, 12)
+GLOBAL_VAR_CONST(access_external_airlocks, 13)
+GLOBAL_VAR_CONST(access_emergency_storage, 14)
+GLOBAL_VAR_CONST(access_change_ids, 15)
+GLOBAL_VAR_CONST(access_ai_upload, 16)
+GLOBAL_VAR_CONST(access_teleporter, 17)
+GLOBAL_VAR_CONST(access_eva, 18)
+GLOBAL_VAR_CONST(access_heads, 19)
+GLOBAL_VAR_CONST(access_captain, 20)
+GLOBAL_VAR_CONST(access_all_personal_lockers, 21)
+GLOBAL_VAR_CONST(access_chapel_office, 22)
+GLOBAL_VAR_CONST(access_tech_storage, 23)
+GLOBAL_VAR_CONST(access_atmospherics, 24)
+GLOBAL_VAR_CONST(access_bar, 25)
+GLOBAL_VAR_CONST(access_janitor, 26)
+GLOBAL_VAR_CONST(access_crematorium, 27)
+GLOBAL_VAR_CONST(access_kitchen, 28)
+GLOBAL_VAR_CONST(access_robotics, 29)
+GLOBAL_VAR_CONST(access_rd, 30)
+GLOBAL_VAR_CONST(access_cargo, 31)
+GLOBAL_VAR_CONST(access_construction, 32)
+GLOBAL_VAR_CONST(access_chemistry, 33)
+GLOBAL_VAR_CONST(access_cargo_bot, 34)
+GLOBAL_VAR_CONST(access_hydroponics, 35)
+GLOBAL_VAR_CONST(access_manufacturing, 36)
+GLOBAL_VAR_CONST(access_library, 37)
+GLOBAL_VAR_CONST(access_lawyer, 38)
+GLOBAL_VAR_CONST(access_virology, 39)
+GLOBAL_VAR_CONST(access_cmo, 40)
+GLOBAL_VAR_CONST(access_qm, 41)
+GLOBAL_VAR_CONST(access_court, 42)
+GLOBAL_VAR_CONST(access_surgery, 45)
+GLOBAL_VAR_CONST(access_theatre, 46)
+GLOBAL_VAR_CONST(access_research, 47)
+GLOBAL_VAR_CONST(access_mining, 48)
+GLOBAL_VAR_CONST(access_mining_office, 49) //not in use
+GLOBAL_VAR_CONST(access_mailsorting, 50)
+GLOBAL_VAR_CONST(access_mint, 51)
+GLOBAL_VAR_CONST(access_mint_vault, 52)
+GLOBAL_VAR_CONST(access_heads_vault, 53)
+GLOBAL_VAR_CONST(access_mining_station, 54)
+GLOBAL_VAR_CONST(access_xenobiology, 55)
+GLOBAL_VAR_CONST(access_ce, 56)
+GLOBAL_VAR_CONST(access_hop, 57)
+GLOBAL_VAR_CONST(access_hos, 58)
+GLOBAL_VAR_CONST(access_RC_announce, 59) //Request console announcements
+GLOBAL_VAR_CONST(access_keycard_auth, 60) //Used for events which require at least two people to confirm them
+GLOBAL_VAR_CONST(access_tcomsat, 61) // has access to the entire telecomms satellite / machinery
+GLOBAL_VAR_CONST(access_gateway, 62)
+GLOBAL_VAR_CONST(access_sec_doors, 63) // Security front doors
+GLOBAL_VAR_CONST(access_mineral_storeroom, 64)
+GLOBAL_VAR_CONST(access_minisat, 65)
+GLOBAL_VAR_CONST(access_weapons, 66) //Weapon authorization for secbots
+GLOBAL_VAR_CONST(access_network, 67)
+GLOBAL_VAR_CONST(access_cloning, 68) //Cloning room
+
+ //BEGIN CENTCOM ACCESS
+ /*Should leave plenty of room if we need to add more access levels.
+ Mostly for admin fun times.*/
+GLOBAL_VAR_CONST(access_cent_general, 101)//General facilities.
+GLOBAL_VAR_CONST(access_cent_thunder, 102)//Thunderdome.
+GLOBAL_VAR_CONST(access_cent_specops, 103)//Special Ops.
+GLOBAL_VAR_CONST(access_cent_medical, 104)//Medical/Research
+GLOBAL_VAR_CONST(access_cent_living, 105)//Living quarters.
+GLOBAL_VAR_CONST(access_cent_storage, 106)//Generic storage areas.
+GLOBAL_VAR_CONST(access_cent_teleporter, 107)//Teleporter.
+GLOBAL_VAR_CONST(access_cent_captain, 109)//Captain's office/ID comp/AI.
+GLOBAL_VAR_CONST(access_cent_bar, 110) // The non-existent Centcom Bar
+
+ //The Syndicate
+GLOBAL_VAR_CONST(access_syndicate, 150)//General Syndicate Access
+GLOBAL_VAR_CONST(access_syndicate_leader, 151)//Nuke Op Leader Access
+
+ //Away Missions or Ruins
+ /*For generic away-mission/ruin access. Why would normal crew have access to a long-abandoned derelict
+ or a 2000 year-old temple? */
+GLOBAL_VAR_CONST(access_away_general, 200)//General facilities.
+GLOBAL_VAR_CONST(access_away_maint, 201)//Away maintenance
+GLOBAL_VAR_CONST(access_away_med, 202)//Away medical
+GLOBAL_VAR_CONST(access_away_sec, 203)//Away security
+GLOBAL_VAR_CONST(access_away_engine, 204)//Away engineering
+GLOBAL_VAR_CONST(access_away_generic1, 205)//Away generic access
+GLOBAL_VAR_CONST(access_away_generic2, 206)
+GLOBAL_VAR_CONST(access_away_generic3, 207)
+GLOBAL_VAR_CONST(access_away_generic4, 208)
+
+/obj/var/list/req_access = null
+/obj/var/req_access_txt = "0"
+/obj/var/list/req_one_access = null
+/obj/var/req_one_access_txt = "0"
+
+//returns 1 if this mob has sufficient access to use this object
+/obj/proc/allowed(mob/M)
+ //check if it doesn't require any access at all
+ if(src.check_access(null))
+ return TRUE
+ if(issilicon(M))
+ if(ispAI(M))
+ return FALSE
+ return TRUE //AI can do whatever it wants
+ if(IsAdminGhost(M))
+ //Access can't stop the abuse
+ return TRUE
+ else if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ //if they are holding or wearing a card that has access, that works
+ if(check_access(H.get_active_held_item()) || src.check_access(H.wear_id))
+ return TRUE
+ else if(ismonkey(M) || isalienadult(M))
+ var/mob/living/carbon/george = M
+ //they can only hold things :(
+ if(check_access(george.get_active_held_item()))
+ return TRUE
+ else if(isanimal(M))
+ var/mob/living/simple_animal/A = M
+ if(check_access(A.get_active_held_item()) || check_access(A.access_card))
+ return TRUE
+ return FALSE
+
+/obj/item/proc/GetAccess()
+ return list()
+
+/obj/item/proc/GetID()
+ return null
+
+//Call this before using req_access or req_one_access directly
+/obj/proc/gen_access()
+ //These generations have been moved out of /obj/New() because they were slowing down the creation of objects that never even used the access system.
+ if(!src.req_access)
+ src.req_access = list()
+ if(src.req_access_txt)
+ var/list/req_access_str = splittext(req_access_txt,";")
+ for(var/x in req_access_str)
+ var/n = text2num(x)
+ if(n)
+ req_access += n
+
+ if(!src.req_one_access)
+ src.req_one_access = list()
+ if(src.req_one_access_txt)
+ var/list/req_one_access_str = splittext(req_one_access_txt,";")
+ for(var/x in req_one_access_str)
+ var/n = text2num(x)
+ if(n)
+ req_one_access += n
+
+/obj/proc/check_access(obj/item/I)
+ gen_access()
+
+ if(!istype(src.req_access, /list)) //something's very wrong
+ return TRUE
+
+ var/list/L = src.req_access
+ if(!L.len && (!src.req_one_access || !src.req_one_access.len)) //no requirements
+ return TRUE
+ if(!I)
+ return FALSE
+ for(var/req in src.req_access)
+ if(!(req in I.GetAccess())) //doesn't have this access
+ return FALSE
+ if(src.req_one_access && src.req_one_access.len)
+ for(var/req in src.req_one_access)
+ if(req in I.GetAccess()) //has an access from the single access list
+ return TRUE
+ return FALSE
+ return TRUE
+
+
+/obj/proc/check_access_list(list/L)
+ if(!src.req_access && !src.req_one_access)
+ return TRUE
+ if(!istype(src.req_access, /list))
+ return TRUE
+ if(!src.req_access.len && (!src.req_one_access || !src.req_one_access.len))
+ return TRUE
+ if(!L)
+ return FALSE
+ if(!istype(L, /list))
+ return FALSE
+ for(var/req in src.req_access)
+ if(!(req in L)) //doesn't have this access
+ return FALSE
+ if(src.req_one_access && src.req_one_access.len)
+ for(var/req in src.req_one_access)
+ if(req in L) //has an access from the single access list
+ return TRUE
+ return FALSE
+ return TRUE
+
+/proc/get_centcom_access(job)
+ switch(job)
+ if("VIP Guest")
+ return list(GLOB.access_cent_general)
+ if("Custodian")
+ return list(GLOB.access_cent_general, GLOB.access_cent_living, GLOB.access_cent_storage)
+ if("Thunderdome Overseer")
+ return list(GLOB.access_cent_general, GLOB.access_cent_thunder)
+ if("Centcom Official")
+ return list(GLOB.access_cent_general, GLOB.access_cent_living)
+ if("Medical Officer")
+ return list(GLOB.access_cent_general, GLOB.access_cent_living, GLOB.access_cent_medical)
+ if("Death Commando")
+ return list(GLOB.access_cent_general, GLOB.access_cent_specops, GLOB.access_cent_living, GLOB.access_cent_storage)
+ if("Research Officer")
+ return list(GLOB.access_cent_general, GLOB.access_cent_specops, GLOB.access_cent_medical, GLOB.access_cent_teleporter, GLOB.access_cent_storage)
+ if("Special Ops Officer")
+ return list(GLOB.access_cent_general, GLOB.access_cent_thunder, GLOB.access_cent_specops, GLOB.access_cent_living, GLOB.access_cent_storage)
+ if("Admiral")
+ return get_all_centcom_access()
+ if("Centcom Commander")
+ return get_all_centcom_access()
+ if("Emergency Response Team Commander")
+ return get_ert_access("commander")
+ if("Security Response Officer")
+ return get_ert_access("sec")
+ if("Engineer Response Officer")
+ return get_ert_access("eng")
+ if("Medical Response Officer")
+ return get_ert_access("med")
+ if("Centcom Bartender")
+ return list(GLOB.access_cent_general, GLOB.access_cent_living, GLOB.access_cent_bar)
+
+/proc/get_all_accesses()
+ return list(GLOB.access_security, GLOB.access_sec_doors, GLOB.access_brig, GLOB.access_armory, GLOB.access_forensics_lockers, GLOB.access_court,
+ GLOB.access_medical, GLOB.access_genetics, GLOB.access_morgue, GLOB.access_rd,
+ GLOB.access_tox, GLOB.access_tox_storage, GLOB.access_chemistry, GLOB.access_engine, GLOB.access_engine_equip, GLOB.access_maint_tunnels,
+ GLOB.access_external_airlocks, GLOB.access_change_ids, GLOB.access_ai_upload,
+ GLOB.access_teleporter, GLOB.access_eva, GLOB.access_heads, GLOB.access_captain, GLOB.access_all_personal_lockers,
+ GLOB.access_tech_storage, GLOB.access_chapel_office, GLOB.access_atmospherics, GLOB.access_kitchen,
+ GLOB.access_bar, GLOB.access_janitor, GLOB.access_crematorium, GLOB.access_robotics, GLOB.access_cargo, GLOB.access_construction,
+ GLOB.access_hydroponics, GLOB.access_library, GLOB.access_lawyer, GLOB.access_virology, GLOB.access_cmo, GLOB.access_qm, GLOB.access_surgery,
+ GLOB.access_theatre, GLOB.access_research, GLOB.access_mining, GLOB.access_mailsorting, GLOB.access_weapons,
+ GLOB.access_heads_vault, GLOB.access_mining_station, GLOB.access_xenobiology, GLOB.access_ce, GLOB.access_hop, GLOB.access_hos, GLOB.access_RC_announce,
+ GLOB.access_keycard_auth, GLOB.access_tcomsat, GLOB.access_gateway, GLOB.access_mineral_storeroom, GLOB.access_minisat, GLOB.access_network, GLOB.access_cloning)
+
+/proc/get_all_centcom_access()
+ return list(GLOB.access_cent_general, GLOB.access_cent_thunder, GLOB.access_cent_specops, GLOB.access_cent_medical, GLOB.access_cent_living, GLOB.access_cent_storage, GLOB.access_cent_teleporter, GLOB.access_cent_captain)
+
+/proc/get_ert_access(class)
+ switch(class)
+ if("commander")
+ return get_all_centcom_access()
+ if("sec")
+ return list(GLOB.access_cent_general, GLOB.access_cent_specops, GLOB.access_cent_living)
+ if("eng")
+ return list(GLOB.access_cent_general, GLOB.access_cent_specops, GLOB.access_cent_living, GLOB.access_cent_storage)
+ if("med")
+ return list(GLOB.access_cent_general, GLOB.access_cent_specops, GLOB.access_cent_medical, GLOB.access_cent_living)
+
+/proc/get_all_syndicate_access()
+ return list(GLOB.access_syndicate, GLOB.access_syndicate)
+
+/proc/get_region_accesses(code)
+ switch(code)
+ if(0)
+ return get_all_accesses()
+ if(1) //station general
+ return list(GLOB.access_kitchen,GLOB.access_bar, GLOB.access_hydroponics, GLOB.access_janitor, GLOB.access_chapel_office, GLOB.access_crematorium, GLOB.access_library, GLOB.access_theatre, GLOB.access_lawyer)
+ if(2) //security
+ return list(GLOB.access_sec_doors, GLOB.access_weapons, GLOB.access_security, GLOB.access_brig, GLOB.access_armory, GLOB.access_forensics_lockers, GLOB.access_court, GLOB.access_hos)
+ if(3) //medbay
+ return list(GLOB.access_medical, GLOB.access_genetics, GLOB.access_cloning, GLOB.access_morgue, GLOB.access_chemistry, GLOB.access_virology, GLOB.access_surgery, GLOB.access_cmo)
+ if(4) //research
+ return list(GLOB.access_research, GLOB.access_tox, GLOB.access_tox_storage, GLOB.access_genetics, GLOB.access_robotics, GLOB.access_xenobiology, GLOB.access_minisat, GLOB.access_rd, GLOB.access_network)
+ if(5) //engineering and maintenance
+ return list(GLOB.access_construction, GLOB.access_maint_tunnels, GLOB.access_engine, GLOB.access_engine_equip, GLOB.access_external_airlocks, GLOB.access_tech_storage, GLOB.access_atmospherics, GLOB.access_tcomsat, GLOB.access_minisat, GLOB.access_ce)
+ if(6) //supply
+ return list(GLOB.access_mailsorting, GLOB.access_mining, GLOB.access_mining_station, GLOB.access_mineral_storeroom, GLOB.access_cargo, GLOB.access_qm)
+ if(7) //command
+ return list(GLOB.access_heads, GLOB.access_RC_announce, GLOB.access_keycard_auth, GLOB.access_change_ids, GLOB.access_ai_upload, GLOB.access_teleporter, GLOB.access_eva, GLOB.access_gateway, GLOB.access_all_personal_lockers, GLOB.access_heads_vault, GLOB.access_hop, GLOB.access_captain)
+
+/proc/get_region_accesses_name(code)
+ switch(code)
+ if(0)
+ return "All"
+ if(1) //station general
+ return "General"
+ if(2) //security
+ return "Security"
+ if(3) //medbay
+ return "Medbay"
+ if(4) //research
+ return "Research"
+ if(5) //engineering and maintenance
+ return "Engineering"
+ if(6) //supply
+ return "Supply"
+ if(7) //command
+ return "Command"
+
+/proc/get_access_desc(A)
+ switch(A)
+ if(GLOB.access_cargo)
+ return "Cargo Bay"
+ if(GLOB.access_cargo_bot)
+ return "Delivery Chutes"
+ if(GLOB.access_security)
+ return "Security"
+ if(GLOB.access_brig)
+ return "Holding Cells"
+ if(GLOB.access_court)
+ return "Courtroom"
+ if(GLOB.access_forensics_lockers)
+ return "Forensics"
+ if(GLOB.access_medical)
+ return "Medical"
+ if(GLOB.access_genetics)
+ return "Genetics Lab"
+ if(GLOB.access_morgue)
+ return "Morgue"
+ if(GLOB.access_tox)
+ return "R&D Lab"
+ if(GLOB.access_tox_storage)
+ return "Toxins Lab"
+ if(GLOB.access_chemistry)
+ return "Chemistry Lab"
+ if(GLOB.access_rd)
+ return "RD Office"
+ if(GLOB.access_bar)
+ return "Bar"
+ if(GLOB.access_janitor)
+ return "Custodial Closet"
+ if(GLOB.access_engine)
+ return "Engineering"
+ if(GLOB.access_engine_equip)
+ return "Power Equipment"
+ if(GLOB.access_maint_tunnels)
+ return "Maintenance"
+ if(GLOB.access_external_airlocks)
+ return "External Airlocks"
+ if(GLOB.access_emergency_storage)
+ return "Emergency Storage"
+ if(GLOB.access_change_ids)
+ return "ID Console"
+ if(GLOB.access_ai_upload)
+ return "AI Chambers"
+ if(GLOB.access_teleporter)
+ return "Teleporter"
+ if(GLOB.access_eva)
+ return "EVA"
+ if(GLOB.access_heads)
+ return "Bridge"
+ if(GLOB.access_captain)
+ return "Captain"
+ if(GLOB.access_all_personal_lockers)
+ return "Personal Lockers"
+ if(GLOB.access_chapel_office)
+ return "Chapel Office"
+ if(GLOB.access_tech_storage)
+ return "Technical Storage"
+ if(GLOB.access_atmospherics)
+ return "Atmospherics"
+ if(GLOB.access_crematorium)
+ return "Crematorium"
+ if(GLOB.access_armory)
+ return "Armory"
+ if(GLOB.access_construction)
+ return "Construction"
+ if(GLOB.access_kitchen)
+ return "Kitchen"
+ if(GLOB.access_hydroponics)
+ return "Hydroponics"
+ if(GLOB.access_library)
+ return "Library"
+ if(GLOB.access_lawyer)
+ return "Law Office"
+ if(GLOB.access_robotics)
+ return "Robotics"
+ if(GLOB.access_virology)
+ return "Virology"
+ if(GLOB.access_cmo)
+ return "CMO Office"
+ if(GLOB.access_qm)
+ return "Quartermaster"
+ if(GLOB.access_surgery)
+ return "Surgery"
+ if(GLOB.access_theatre)
+ return "Theatre"
+ if(GLOB.access_manufacturing)
+ return "Manufacturing"
+ if(GLOB.access_research)
+ return "Science"
+ if(GLOB.access_mining)
+ return "Mining"
+ if(GLOB.access_mining_office)
+ return "Mining Office"
+ if(GLOB.access_mailsorting)
+ return "Cargo Office"
+ if(GLOB.access_mint)
+ return "Mint"
+ if(GLOB.access_mint_vault)
+ return "Mint Vault"
+ if(GLOB.access_heads_vault)
+ return "Main Vault"
+ if(GLOB.access_mining_station)
+ return "Mining EVA"
+ if(GLOB.access_xenobiology)
+ return "Xenobiology Lab"
+ if(GLOB.access_hop)
+ return "HoP Office"
+ if(GLOB.access_hos)
+ return "HoS Office"
+ if(GLOB.access_ce)
+ return "CE Office"
+ if(GLOB.access_RC_announce)
+ return "RC Announcements"
+ if(GLOB.access_keycard_auth)
+ return "Keycode Auth."
+ if(GLOB.access_tcomsat)
+ return "Telecommunications"
+ if(GLOB.access_gateway)
+ return "Gateway"
+ if(GLOB.access_sec_doors)
+ return "Brig"
+ if(GLOB.access_mineral_storeroom)
+ return "Mineral Storage"
+ if(GLOB.access_minisat)
+ return "AI Satellite"
+ if(GLOB.access_weapons)
+ return "Weapon Permit"
+ if(GLOB.access_network)
+ return "Network Access"
+ if(GLOB.access_cloning)
+ return "Cloning Room"
+
+/proc/get_centcom_access_desc(A)
+ switch(A)
+ if(GLOB.access_cent_general)
+ return "Code Grey"
+ if(GLOB.access_cent_thunder)
+ return "Code Yellow"
+ if(GLOB.access_cent_storage)
+ return "Code Orange"
+ if(GLOB.access_cent_living)
+ return "Code Green"
+ if(GLOB.access_cent_medical)
+ return "Code White"
+ if(GLOB.access_cent_teleporter)
+ return "Code Blue"
+ if(GLOB.access_cent_specops)
+ return "Code Black"
+ if(GLOB.access_cent_captain)
+ return "Code Gold"
+ if(GLOB.access_cent_bar)
+ return "Code Scotch"
+
+/proc/get_all_jobs()
+ return list("Assistant", "Captain", "Head of Personnel", "Bartender", "Cook", "Botanist", "Quartermaster", "Cargo Technician",
+ "Shaft Miner", "Clown", "Mime", "Janitor", "Curator", "Lawyer", "Chaplain", "Chief Engineer", "Station Engineer",
+ "Atmospheric Technician", "Chief Medical Officer", "Medical Doctor", "Chemist", "Geneticist", "Virologist",
+ "Research Director", "Scientist", "Roboticist", "Head of Security", "Warden", "Detective", "Security Officer")
+
+/proc/get_all_job_icons() //For all existing HUD icons
+ return get_all_jobs() + list("Prisoner")
+
+/proc/get_all_centcom_jobs()
+ return list("VIP Guest","Custodian","Thunderdome Overseer","Centcom Official","Medical Officer","Death Commando","Research Officer","Special Ops Officer","Admiral","Centcom Commander","Emergency Response Team Commander","Security Response Officer","Engineer Response Officer", "Medical Response Officer","Centcom Bartender")
+
+/obj/item/proc/GetJobName() //Used in secHUD icon generation
+ var/obj/item/weapon/card/id/I = GetID()
+ if(!I)
+ return
+ var/jobName = I.assignment
+ if(jobName in get_all_job_icons()) //Check if the job has a hud icon
+ return jobName
+ if(jobName in get_all_centcom_jobs()) //Return with the NT logo if it is a Centcom job
+ return "Centcom"
+ return "Unknown" //Return unknown if none of the above apply
diff --git a/code/modules/jobs/job_types/civilian.dm b/code/modules/jobs/job_types/civilian.dm
index 7d983e5519..062834ca03 100644
--- a/code/modules/jobs/job_types/civilian.dm
+++ b/code/modules/jobs/job_types/civilian.dm
@@ -35,8 +35,8 @@ Clown
/obj/item/weapon/reagent_containers/spray/waterflower = 1,
/obj/item/weapon/reagent_containers/food/snacks/grown/banana = 1,
/obj/item/device/megaphone/clown = 1,
- /obj/item/weapon/reagent_containers/food/drinks/soda_cans/canned_laughter = 1,
- /obj/item/weapon/pneumatic_cannon/pie = 1
+ /obj/item/weapon/reagent_containers/food/drinks/soda_cans/canned_laughter = 1,
+ /obj/item/weapon/pneumatic_cannon/pie = 1
)
implants = list(/obj/item/weapon/implant/sad_trombone)
@@ -129,7 +129,7 @@ Curator
outfit = /datum/outfit/job/curator
access = list(GLOB.access_library)
- minimal_access = list(GLOB.access_library, GLOB.access_construction,GLOB.access_mining_station)
+ minimal_access = list(GLOB.access_library, GLOB.access_construction,GLOB.access_mining_station)
/datum/outfit/job/curator
name = "Curator"
diff --git a/code/modules/jobs/jobs.dm b/code/modules/jobs/jobs.dm
index 53a1fed47b..2d7caa5fc4 100644
--- a/code/modules/jobs/jobs.dm
+++ b/code/modules/jobs/jobs.dm
@@ -1,109 +1,109 @@
-GLOBAL_LIST_INIT(command_positions, list(
- "Captain",
- "Head of Personnel",
- "Head of Security",
- "Chief Engineer",
- "Research Director",
- "Chief Medical Officer"))
-
-
-GLOBAL_LIST_INIT(engineering_positions, list(
- "Chief Engineer",
- "Station Engineer",
- "Atmospheric Technician"))
-
-
-GLOBAL_LIST_INIT(medical_positions, list(
- "Chief Medical Officer",
- "Medical Doctor",
- "Geneticist",
- "Virologist",
- "Chemist"))
-
-
-GLOBAL_LIST_INIT(science_positions, list(
- "Research Director",
- "Scientist",
- "Roboticist"))
-
-
-GLOBAL_LIST_INIT(supply_positions, list(
- "Head of Personnel",
- "Quartermaster",
- "Cargo Technician",
- "Shaft Miner"))
-
-
-GLOBAL_LIST_INIT(civilian_positions, list(
- "Bartender",
- "Botanist",
- "Cook",
- "Janitor",
- "Curator",
- "Lawyer",
- "Chaplain",
- "Clown",
- "Mime",
- "Assistant"))
-
-
-GLOBAL_LIST_INIT(security_positions, list(
- "Head of Security",
- "Warden",
- "Detective",
- "Security Officer"))
-
-
-GLOBAL_LIST_INIT(nonhuman_positions, list(
- "AI",
- "Cyborg",
- "pAI"))
-
-
-/proc/guest_jobbans(job)
- return ((job in GLOB.command_positions) || (job in GLOB.nonhuman_positions) || (job in GLOB.security_positions))
-
-
-
-//this is necessary because antags happen before job datums are handed out, but NOT before they come into existence
-//so I can't simply use job datum.department_head straight from the mind datum, laaaaame.
-/proc/get_department_heads(var/job_title)
- if(!job_title)
- return list()
-
- for(var/datum/job/J in SSjob.occupations)
- if(J.title == job_title)
- return J.department_head //this is a list
-
-/proc/get_full_job_name(job)
- var/static/regex/cap_expand = new("cap(?!tain)")
- var/static/regex/cmo_expand = new("cmo")
- var/static/regex/hos_expand = new("hos")
- var/static/regex/hop_expand = new("hop")
- var/static/regex/rd_expand = new("rd")
- var/static/regex/ce_expand = new("ce")
- var/static/regex/qm_expand = new("qm")
- var/static/regex/sec_expand = new("(?pAI Controlled"
- else
- return "Autonomous"
- else if(!on)
- return "Inactive"
- else if(!mode)
- return "Idle"
- else
- return "[mode_name[mode]]"
-
-/mob/living/simple_animal/bot/proc/turn_on()
- if(stat)
- return 0
- on = 1
- set_light(initial(light_range))
- update_icon()
- diag_hud_set_botstat()
- return 1
-
-/mob/living/simple_animal/bot/proc/turn_off()
- on = 0
- set_light(0)
- bot_reset() //Resets an AI's call, should it exist.
- update_icon()
-
-/mob/living/simple_animal/bot/Initialize()
- ..()
- access_card = new /obj/item/weapon/card/id(src)
-//This access is so bots can be immediately set to patrol and leave Robotics, instead of having to be let out first.
- access_card.access += GLOB.access_robotics
- set_custom_texts()
- Radio = new/obj/item/device/radio(src)
- if(radio_key)
- Radio.keyslot = new radio_key
- Radio.subspace_transmission = 1
- Radio.canhear_range = 0 // anything greater will have the bot broadcast the channel as if it were saying it out loud.
- Radio.recalculateChannels()
-
- bot_core = new bot_core_type(src)
-
- //Adds bot to the diagnostic HUD system
- prepare_huds()
- var/datum/atom_hud/data/diagnostic/diag_hud = GLOB.huds[DATA_HUD_DIAGNOSTIC]
- diag_hud.add_to_hud(src)
- diag_hud_set_bothealth()
- diag_hud_set_botstat()
- diag_hud_set_botmode()
-
- //Gives a HUD view to player bots that use a HUD.
- activate_data_hud()
-
-
-/mob/living/simple_animal/bot/update_canmove()
- . = ..()
- if(!on)
- . = 0
- canmove = .
-
-/mob/living/simple_animal/bot/Destroy()
- if(paicard)
- ejectpai()
- qdel(Radio)
- qdel(access_card)
- qdel(bot_core)
- return ..()
-
-/mob/living/simple_animal/bot/bee_friendly()
- return 1
-
-/mob/living/simple_animal/bot/death(gibbed)
- explode()
- ..()
-
-/mob/living/simple_animal/bot/proc/explode()
- qdel(src)
-
-/mob/living/simple_animal/bot/emag_act(mob/user)
- if(locked) //First emag application unlocks the bot's interface. Apply a screwdriver to use the emag again.
- locked = 0
- emagged = 1
- to_chat(user, "You bypass [src]'s controls.")
- return
- if(!locked && open) //Bot panel is unlocked by ID or emag, and the panel is screwed open. Ready for emagging.
- emagged = 2
- remote_disabled = 1 //Manually emagging the bot locks out the AI built in panel.
- locked = 1 //Access denied forever!
- bot_reset()
- turn_on() //The bot automatically turns on when emagged, unless recently hit with EMP.
- to_chat(src, "(#$*#$^^( OVERRIDE DETECTED")
- add_logs(user, src, "emagged")
- return
- else //Bot is unlocked, but the maint panel has not been opened with a screwdriver yet.
- to_chat(user, "You need to open maintenance panel first!")
-
-/mob/living/simple_animal/bot/examine(mob/user)
- ..()
- if(health < maxHealth)
- if(health > maxHealth/3)
- to_chat(user, "[src]'s parts look loose.")
- else
- to_chat(user, "[src]'s parts look very loose!")
- else
- to_chat(user, "[src] is in pristine condition.")
-
-/mob/living/simple_animal/bot/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
- if(amount>0 && prob(10))
- new /obj/effect/decal/cleanable/oil(loc)
- . = ..()
-
-/mob/living/simple_animal/bot/updatehealth()
- ..()
- diag_hud_set_bothealth()
-
-/mob/living/simple_animal/bot/med_hud_set_health()
- return //we use a different hud
-
-/mob/living/simple_animal/bot/med_hud_set_status()
- return //we use a different hud
-
-/mob/living/simple_animal/bot/handle_automated_action() //Master process which handles code common across most bots.
- set background = BACKGROUND_ENABLED
- diag_hud_set_botmode()
-
- if(!on || client)
- return
-
- switch(mode) //High-priority overrides are processed first. Bots can do nothing else while under direct command.
- if(BOT_RESPONDING) //Called by the AI.
- call_mode()
- return
- if(BOT_SUMMON) //Called by PDA
- bot_summon()
- return
- return 1 //Successful completion. Used to prevent child process() continuing if this one is ended early.
-
-
-/mob/living/simple_animal/bot/attack_hand(mob/living/carbon/human/H)
- if(H.a_intent == INTENT_HELP)
- interact(H)
- else
- return ..()
-
-/mob/living/simple_animal/bot/attack_ai(mob/user)
- if(!topic_denied(user))
- interact(user)
- else
- to_chat(user, "[src]'s interface is not responding!")
-
-/mob/living/simple_animal/bot/interact(mob/user)
- show_controls(user)
-
-/mob/living/simple_animal/bot/attackby(obj/item/weapon/W, mob/user, params)
- if(istype(W, /obj/item/weapon/screwdriver))
- if(!locked)
- open = !open
- to_chat(user, "The maintenance panel is now [open ? "opened" : "closed"].")
- else
- to_chat(user, "The maintenance panel is locked.")
- else if(istype(W, /obj/item/weapon/card/id) || istype(W, /obj/item/device/pda))
- if(bot_core.allowed(user) && !open && !emagged)
- locked = !locked
- to_chat(user, "Controls are now [locked ? "locked." : "unlocked."]")
- else
- if(emagged)
- to_chat(user, "ERROR")
- if(open)
- to_chat(user, "Please close the access panel before locking it.")
- else
- to_chat(user, "Access denied.")
- else if(istype(W, /obj/item/device/paicard))
- insertpai(user, W)
- else if(istype(W, /obj/item/weapon/hemostat) && paicard)
- if(open)
- to_chat(user, "Close the access panel before manipulating the personality slot!")
- else
- to_chat(user, "You attempt to pull [paicard] free...")
- if(do_after(user, 30, target = src))
- if (paicard)
- user.visible_message("[user] uses [W] to pull [paicard] out of [bot_name]!","You pull [paicard] out of [bot_name] with [W].")
- ejectpai(user)
- else
- user.changeNext_move(CLICK_CD_MELEE)
- if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != INTENT_HARM)
- if(health >= maxHealth)
- to_chat(user, "[src] does not need a repair!")
- return
- if(!open)
- to_chat(user, "Unable to repair with the maintenance panel closed!")
- return
- var/obj/item/weapon/weldingtool/WT = W
- if(WT.remove_fuel(0, user))
- adjustHealth(-10)
- user.visible_message("[user] repairs [src]!","You repair [src].")
- else
- to_chat(user, "The welder must be on for this task!")
- else
- if(W.force) //if force is non-zero
- do_sparks(5, TRUE, src)
- ..()
-
-/mob/living/simple_animal/bot/bullet_act(obj/item/projectile/Proj)
- if(Proj && (Proj.damage_type == BRUTE || Proj.damage_type == BURN))
- if(prob(75) && Proj.damage > 0)
- do_sparks(5, TRUE, src)
- return ..()
-
-/mob/living/simple_animal/bot/emp_act(severity)
- var/was_on = on
- stat |= EMPED
- new /obj/effect/overlay/temp/emp(loc)
- if(paicard)
- paicard.emp_act(severity)
- src.visible_message("[paicard] is flies out of [bot_name]!","You are forcefully ejected from [bot_name]!")
- ejectpai(0)
- if(on)
- turn_off()
- spawn(severity*300)
- stat &= ~EMPED
- if(was_on)
- turn_on()
-
-/mob/living/simple_animal/bot/proc/set_custom_texts() //Superclass for setting hack texts. Appears only if a set is not given to a bot locally.
- text_hack = "You hack [name]."
- text_dehack = "You reset [name]."
- text_dehack_fail = "You fail to reset [name]."
-
-/mob/living/simple_animal/bot/proc/speak(message,channel) //Pass a message to have the bot say() it. Pass a frequency to say it on the radio.
- if((!on) || (!message))
- return
- if(channel && Radio.channels[channel])// Use radio if we have channel key
- Radio.talk_into(src, message, channel, get_spans(), get_default_language())
- else
- say(message)
-
-/mob/living/simple_animal/bot/get_spans()
- return ..() | SPAN_ROBOT
-
-/mob/living/simple_animal/bot/radio(message, message_mode, list/spans, language)
- . = ..()
- if(. != 0)
- return .
-
- switch(message_mode)
- if(MODE_HEADSET)
- Radio.talk_into(src, message, , spans, language)
- return REDUCE_RANGE
-
- if(MODE_DEPARTMENT)
- Radio.talk_into(src, message, message_mode, spans, language)
- return REDUCE_RANGE
-
- if(message_mode in GLOB.radiochannels)
- Radio.talk_into(src, message, message_mode, spans, language)
- return REDUCE_RANGE
- return 0
-
-//Generalized behavior code, override where needed!
-
-/*
-scan() will search for a given type (such as turfs, human mobs, or objects) in the bot's view range, and return a single result.
-Arguments: The object type to be searched (such as "/mob/living/carbon/human"), the old scan result to be ignored, if one exists,
-and the view range, which defaults to 7 (full screen) if an override is not passed.
-If the bot maintains an ignore list, it is also checked here.
-
-Example usage: patient = scan(/mob/living/carbon/human, oldpatient, 1)
-The proc would return a human next to the bot to be set to the patient var.
-Pass the desired type path itself, declaring a temporary var beforehand is not required.
-*/
-/mob/living/simple_animal/bot/proc/scan(scan_type, old_target, scan_range = DEFAULT_SCAN_RANGE)
- var/turf/T = get_turf(src)
- if(!T)
- return
- var/list/adjacent = T.GetAtmosAdjacentTurfs(1)
- if(shuffle) //If we were on the same tile as another bot, let's randomize our choices so we dont both go the same way
- adjacent = shuffle(adjacent)
- shuffle = FALSE
- for(var/scan in adjacent)//Let's see if there's something right next to us first!
- if(check_bot(scan)) //Is there another bot there? Then let's just skip it
- continue
- if(isturf(scan_type)) //If we're lookeing for a turf we can just run the checks directly!
- var/final_result = checkscan(scan,scan_type,old_target)
- if(final_result)
- return final_result
- else
- var/turf/turfy = scan
- for(var/deepscan in turfy.contents)//Check the contents since adjacent is turfs
- var/final_result = checkscan(deepscan,scan_type,old_target)
- if(final_result)
- return final_result
- for (var/scan in shuffle(view(scan_range, src))-adjacent) //Search for something in range!
- var/final_result = checkscan(scan,scan_type,old_target)
- if(final_result)
- return final_result
-
-/mob/living/simple_animal/bot/proc/checkscan(scan, scan_type, old_target)
- if(!istype(scan, scan_type)) //Check that the thing we found is the type we want!
- return 0 //If not, keep searching!
- if( (scan in ignore_list) || (scan == old_target) ) //Filter for blacklisted elements, usually unreachable or previously processed oness
- return 0
-
- var/scan_result = process_scan(scan) //Some bots may require additional processing when a result is selected.
- if(scan_result)
- return scan_result
- else
- return 0 //The current element failed assessment, move on to the next.
- return
-
-/mob/living/simple_animal/bot/proc/check_bot(targ)
- var/turf/T = get_turf(targ)
- if(T)
- for(var/C in T.contents)
- if(istype(C,type) && (C != src)) //Is there another bot there already? If so, let's skip it so we dont all atack on top of eachother.
- return 1 //Let's abort if we find a bot so we dont have to keep rechecking
-
-//When the scan finds a target, run bot specific processing to select it for the next step. Empty by default.
-/mob/living/simple_animal/bot/proc/process_scan(scan_target)
- return scan_target
-
-
-/mob/living/simple_animal/bot/proc/add_to_ignore(subject)
- if(ignore_list.len < 50) //This will help keep track of them, so the bot is always trying to reach a blocked spot.
- ignore_list |= subject
- else if(ignore_list.len >= subject) //If the list is full, insert newest, delete oldest.
- ignore_list -= ignore_list[1]
- ignore_list |= subject
-
-/*
-Movement proc for stepping a bot through a path generated through A-star.
-Pass a positive integer as an argument to override a bot's default speed.
-*/
-/mob/living/simple_animal/bot/proc/bot_move(dest, move_speed)
-
- if(!dest || !path || path.len == 0) //A-star failed or a path/destination was not set.
- path = list()
- return 0
- dest = get_turf(dest) //We must always compare turfs, so get the turf of the dest var if dest was originally something else.
- var/turf/last_node = get_turf(path[path.len]) //This is the turf at the end of the path, it should be equal to dest.
- if(get_turf(src) == dest) //We have arrived, no need to move again.
- return 1
- else if(dest != last_node) //The path should lead us to our given destination. If this is not true, we must stop.
- path = list()
- return 0
- var/step_count = move_speed ? move_speed : base_speed //If a value is passed into move_speed, use that instead of the default speed var.
-
- if(step_count >= 1 && tries < BOT_STEP_MAX_RETRIES)
- for(var/step_number = 0, step_number < step_count,step_number++)
- spawn(BOT_STEP_DELAY*step_number)
- bot_step(dest)
- else
- return 0
- return 1
-
-
-/mob/living/simple_animal/bot/proc/bot_step(dest) //Step,increase tries if failed
- if(!path)
- return 0
- if(path.len > 1)
- step_towards(src, path[1])
- if(get_turf(src) == path[1]) //Successful move
- path -= path[1]
- tries = 0
- else
- tries++
- return 0
- else if(path.len == 1)
- step_to(src, dest)
- path = list()
- return 1
-
-
-/mob/living/simple_animal/bot/proc/check_bot_access()
- if(mode != BOT_SUMMON && mode != BOT_RESPONDING)
- access_card.access = prev_access
-
-/mob/living/simple_animal/bot/proc/call_bot(caller, turf/waypoint, message=TRUE)
- bot_reset() //Reset a bot before setting it to call mode.
- var/area/end_area = get_area(waypoint)
-
- if(client) //Player bots instead get a location command from the AI
- to_chat(src, "Priority waypoint set by \icon[caller] [caller]. Proceed to [end_area.name]<\b>.")
-
- //For giving the bot temporary all-access.
- var/obj/item/weapon/card/id/all_access = new /obj/item/weapon/card/id
- var/datum/job/captain/All = new/datum/job/captain
- all_access.access = All.get_access()
-
- path = get_path_to(src, waypoint, /turf/proc/Distance_cardinal, 0, 200, id=all_access)
- calling_ai = caller //Link the AI to the bot!
- ai_waypoint = waypoint
-
- if(path && path.len) //Ensures that a valid path is calculated!
- if(!on)
- turn_on() //Saves the AI the hassle of having to activate a bot manually.
- access_card = all_access //Give the bot all-access while under the AI's command.
- if(message)
- to_chat(calling_ai, "\icon[src] [name] called to [end_area.name]. [path.len-1] meters to destination.")
- pathset = 1
- mode = BOT_RESPONDING
- tries = 0
- else
- if(message)
- to_chat(calling_ai, "Failed to calculate a valid route. Ensure destination is clear of obstructions and within range.")
- calling_ai = null
- path = list()
-
-/mob/living/simple_animal/bot/proc/call_mode() //Handles preparing a bot for a call, as well as calling the move proc.
-//Handles the bot's movement during a call.
- var/success = bot_move(ai_waypoint, 3)
- if(!success)
- if(calling_ai)
- to_chat(calling_ai, "\icon[src] [get_turf(src) == ai_waypoint ? "[src] successfully arrived to waypoint." : "[src] failed to reach waypoint."]")
- calling_ai = null
- bot_reset()
-
-/mob/living/simple_animal/bot/proc/bot_reset()
- if(calling_ai) //Simple notification to the AI if it called a bot. It will not know the cause or identity of the bot.
- to_chat(calling_ai, "Call command to a bot has been reset.")
- calling_ai = null
- path = list()
- summon_target = null
- pathset = 0
- access_card.access = prev_access
- tries = 0
- mode = BOT_IDLE
- diag_hud_set_botstat()
- diag_hud_set_botmode()
-
-
-
-
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//Patrol and summon code!
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-/mob/living/simple_animal/bot/proc/bot_patrol()
- patrol_step()
- spawn(5)
- if(mode == BOT_PATROL)
- patrol_step()
- return
-
-/mob/living/simple_animal/bot/proc/start_patrol()
-
- if(tries >= BOT_STEP_MAX_RETRIES) //Bot is trapped, so stop trying to patrol.
- auto_patrol = 0
- tries = 0
- speak("Unable to start patrol.")
-
- return
-
- if(!auto_patrol) //A bot not set to patrol should not be patrolling.
- mode = BOT_IDLE
- return
-
- if(patrol_target) // has patrol target
- spawn(0)
- calc_path() // Find a route to it
- if(path.len == 0)
- patrol_target = null
- return
- mode = BOT_PATROL
- else // no patrol target, so need a new one
- speak("Engaging patrol mode.")
- find_patrol_target()
- tries++
- return
-
-// perform a single patrol step
-
-/mob/living/simple_animal/bot/proc/patrol_step()
-
- if(client) // In use by player, don't actually move.
- return
-
- if(loc == patrol_target) // reached target
- //Find the next beacon matching the target.
- if(!get_next_patrol_target())
- find_patrol_target() //If it fails, look for the nearest one instead.
- return
-
- else if(path.len > 0 && patrol_target) // valid path
- var/turf/next = path[1]
- if(next == loc)
- path -= next
- return
-
-
- var/moved = bot_move(patrol_target)//step_towards(src, next) // attempt to move
- if(!moved) //Couldn't proceed the next step of the path BOT_STEP_MAX_RETRIES times
- spawn(2)
- calc_path()
- if(path.len == 0)
- find_patrol_target()
- tries = 0
-
- else // no path, so calculate new one
- mode = BOT_START_PATROL
-
-// finds the nearest beacon to self
-/mob/living/simple_animal/bot/proc/find_patrol_target()
- nearest_beacon = null
- new_destination = null
- find_nearest_beacon()
- if(nearest_beacon)
- patrol_target = nearest_beacon_loc
- destination = next_destination
- else
- auto_patrol = 0
- mode = BOT_IDLE
- speak("Disengaging patrol mode.")
-
-/mob/living/simple_animal/bot/proc/get_next_patrol_target()
- // search the beacon list for the next target in the list.
- for(var/obj/machinery/navbeacon/NB in GLOB.navbeacons["[z]"])
- if(NB.location == next_destination) //Does the Beacon location text match the destination?
- destination = new_destination //We now know the name of where we want to go.
- patrol_target = NB.loc //Get its location and set it as the target.
- next_destination = NB.codes["next_patrol"] //Also get the name of the next beacon in line.
- return 1
-
-/mob/living/simple_animal/bot/proc/find_nearest_beacon()
- for(var/obj/machinery/navbeacon/NB in GLOB.navbeacons["[z]"])
- var/dist = get_dist(src, NB)
- if(nearest_beacon) //Loop though the beacon net to find the true closest beacon.
- //Ignore the beacon if were are located on it.
- if(dist>1 && dist 1) //Begin the search, save this one for comparison on the next loop.
- nearest_beacon = NB.location
- nearest_beacon_loc = NB.loc
- patrol_target = nearest_beacon_loc
- destination = nearest_beacon
-
-//PDA control. Some bots, especially MULEs, may have more parameters.
-/mob/living/simple_animal/bot/proc/bot_control(command, mob/user, turf/user_turf, list/user_access = list())
- if(!on || emagged == 2 || remote_disabled) //Emagged bots do not respect anyone's authority! Bots with their remote controls off cannot get commands.
- return 1 //ACCESS DENIED
- if(client)
- bot_control_message(command,user,user_turf,user_access)
- // process control input
- switch(command)
- if("patroloff")
- bot_reset() //HOLD IT!!
- auto_patrol = 0
-
- if("patrolon")
- auto_patrol = 1
-
- if("summon")
- bot_reset()
- summon_target = user_turf
- if(user_access.len != 0)
- access_card.access = user_access + prev_access //Adds the user's access, if any.
- mode = BOT_SUMMON
- speak("Responding.", radio_channel)
- calc_summon_path()
-
- if("ejectpai")
- ejectpairemote(user)
- return
-
-//
-/mob/living/simple_animal/bot/proc/bot_control_message(command,user,user_turf,user_access)
- switch(command)
- if("patroloff")
- to_chat(src, "STOP PATROL")
- if("patrolon")
- to_chat(src, "START PATROL")
- if("summon")
- var/area/a = get_area(user_turf)
- to_chat(src, "PRIORITY ALERT:[user] in [a.name]!")
- if("stop")
- to_chat(src, "STOP!")
-
- if("go")
- to_chat(src, "GO!")
-
- if("home")
- to_chat(src, "RETURN HOME!")
- if("ejectpai")
- return
- else
- to_chat(src, "Unidentified control sequence recieved:[command]")
-
-/mob/living/simple_animal/bot/proc/bot_summon() // summoned to PDA
- summon_step()
-
-// calculates a path to the current destination
-// given an optional turf to avoid
-/mob/living/simple_animal/bot/proc/calc_path(turf/avoid)
- check_bot_access()
- path = get_path_to(src, patrol_target, /turf/proc/Distance_cardinal, 0, 120, id=access_card, exclude=avoid)
-
-/mob/living/simple_animal/bot/proc/calc_summon_path(turf/avoid)
- check_bot_access()
- spawn()
- path = get_path_to(src, summon_target, /turf/proc/Distance_cardinal, 0, 150, id=access_card, exclude=avoid)
- if(!path.len) //Cannot reach target. Give up and announce the issue.
- speak("Summon command failed, destination unreachable.",radio_channel)
- bot_reset()
-
-/mob/living/simple_animal/bot/proc/summon_step()
-
- if(client) // In use by player, don't actually move.
- return
-
- if(loc == summon_target) // Arrived to summon location.
- bot_reset()
- return
-
- else if(path.len > 0 && summon_target) //Proper path acquired!
- var/turf/next = path[1]
- if(next == loc)
- path -= next
- return
-
- var/moved = bot_move(summon_target, 3) // Move attempt
- if(!moved)
- spawn(2)
- calc_summon_path()
- tries = 0
-
- else // no path, so calculate new one
- calc_summon_path()
-
-/mob/living/simple_animal/bot/Bump(M as mob|obj) //Leave no door unopened!
- . = ..()
- if((istype(M, /obj/machinery/door/airlock) || istype(M, /obj/machinery/door/window)) && (!isnull(access_card)))
- var/obj/machinery/door/D = M
- if(D.check_access(access_card))
- D.open()
- frustration = 0
-
-/mob/living/simple_animal/bot/proc/show_controls(mob/M)
- users |= M
- var/dat = ""
- dat = get_controls(M)
- var/datum/browser/popup = new(M,window_id,window_name,350,600)
- popup.set_content(dat)
- popup.open(use_onclose = 0)
- onclose(M,window_id,ref=src)
- return
-
-/mob/living/simple_animal/bot/proc/update_controls()
- for(var/mob/M in users)
- show_controls(M)
-
-/mob/living/simple_animal/bot/proc/get_controls(mob/M)
- return "PROTOBOT - NOT FOR USE"
-
-/mob/living/simple_animal/bot/Topic(href, href_list)
- //No ..() to prevent strip panel showing up - Todo: make that saner
- if(href_list["close"])// HUE HUE
- if(usr in users)
- users.Remove(usr)
- return 1
-
- if(topic_denied(usr))
- to_chat(usr, "[src]'s interface is not responding!")
- return 1
- add_fingerprint(usr)
-
- if((href_list["power"]) && (bot_core.allowed(usr) || !locked))
- if(on)
- turn_off()
- else
- turn_on()
-
- switch(href_list["operation"])
- if("patrol")
- auto_patrol = !auto_patrol
- bot_reset()
- if("remote")
- remote_disabled = !remote_disabled
- if("hack")
- if(emagged != 2)
- emagged = 2
- hacked = 1
- locked = 1
- to_chat(usr, "[text_hack]")
- bot_reset()
- else if(!hacked)
- to_chat(usr, "[text_dehack_fail]")
- else
- emagged = 0
- hacked = 0
- to_chat(usr, "[text_dehack]")
- bot_reset()
- if("ejectpai")
- if(paicard && (!locked || issilicon(usr) || IsAdminGhost(usr)))
- to_chat(usr, "You eject [paicard] from [bot_name]")
- ejectpai(usr)
- update_controls()
-
-/mob/living/simple_animal/bot/proc/update_icon()
- icon_state = "[initial(icon_state)][on]"
-
-// Machinery to simplify topic and access calls
-/obj/machinery/bot_core
- use_power = 0
- var/mob/living/simple_animal/bot/owner = null
-
-/obj/machinery/bot_core/Initialize()
- ..()
- owner = loc
- if(!istype(owner))
- qdel(src)
-
-/mob/living/simple_animal/bot/proc/topic_denied(mob/user) //Access check proc for bot topics! Remember to place in a bot's individual Topic if desired.
- if(!user.canUseTopic(src))
- return 1
- // 0 for access, 1 for denied.
- if(emagged == 2) //An emagged bot cannot be controlled by humans, silicons can if one hacked it.
- if(!hacked) //Manually emagged by a human - access denied to all.
- return 1
- else if(!issilicon(user) && !IsAdminGhost(user)) //Bot is hacked, so only silicons and admins are allowed access.
- return 1
- return 0
-
-/mob/living/simple_animal/bot/proc/hack(mob/user)
- var/hack
- if(issilicon(user) || IsAdminGhost(user)) //Allows silicons or admins to toggle the emag status of a bot.
- hack += "[emagged == 2 ? "Software compromised! Unit may exhibit dangerous or erratic behavior." : "Unit operating normally. Release safety lock?"]
"
- hack += "Harm Prevention Safety System: [emagged ? "DANGER" : "Engaged"]
"
- else if(!locked) //Humans with access can use this option to hide a bot from the AI's remote control panel and PDA control.
- hack += "Remote network control radio: [remote_disabled ? "Disconnected" : "Connected"]
"
- return hack
-
-/mob/living/simple_animal/bot/proc/showpai(mob/user)
- var/eject = ""
- if((!locked || issilicon(usr) || IsAdminGhost(usr)))
- if(paicard || allow_pai)
- eject += "Personality card status: "
- if(paicard)
- if(client)
- eject += "Active"
- else
- eject += "Inactive"
- else if(!allow_pai || key)
- eject += "Unavailable"
- else
- eject += "Not inserted"
- eject += "
"
- eject += "
"
- return eject
-
-/mob/living/simple_animal/bot/proc/insertpai(mob/user, obj/item/device/paicard/card)
- if(paicard)
- to_chat(user, "A [paicard] is already inserted!")
- else if(allow_pai && !key)
- if(!locked && !open)
- if(card.pai && card.pai.mind)
- if(!user.drop_item())
- return
- card.forceMove(src)
- paicard = card
- user.visible_message("[user] inserts [card] into [src]!","You insert [card] into [src].")
- paicard.pai.mind.transfer_to(src)
- to_chat(src, "You sense your form change as you are uploaded into [src].")
- bot_name = name
- name = paicard.pai.name
- faction = user.faction.Copy()
- add_logs(user, paicard.pai, "uploaded to [bot_name],")
- return 1
- else
- to_chat(user, "[card] is inactive.")
- else
- to_chat(user, "The personality slot is locked.")
- else
- to_chat(user, "[src] is not compatible with [card]")
-
-/mob/living/simple_animal/bot/proc/ejectpai(mob/user = null, announce = 1)
- if(paicard)
- if(mind && paicard.pai)
- mind.transfer_to(paicard.pai)
- else if(paicard.pai)
- paicard.pai.key = key
- else
- ghostize(0) // The pAI card that just got ejected was dead.
- key = null
- paicard.forceMove(loc)
- if(user)
- add_logs(user, paicard.pai, "ejected from [src.bot_name],")
- else
- add_logs(src, paicard.pai, "ejected")
- if(announce)
- to_chat(paicard.pai, "You feel your control fade as [paicard] ejects from [bot_name].")
- paicard = null
- name = bot_name
- faction = initial(faction)
-
-/mob/living/simple_animal/bot/proc/ejectpairemote(mob/user)
- if(bot_core.allowed(user) && paicard)
- speak("Ejecting personality chip.", radio_channel)
- ejectpai(user)
-
-/mob/living/simple_animal/bot/Login()
- . = ..()
- access_card.access += player_access
- diag_hud_set_botmode()
- activate_data_hud()
-
-/mob/living/simple_animal/bot/Logout()
- . = ..()
- bot_reset()
-
-/mob/living/simple_animal/bot/revive(full_heal = 0, admin_revive = 0)
- if(..())
- update_icon()
- . = 1
-
-/mob/living/simple_animal/bot/ghost()
- if(stat != DEAD) // Only ghost if we're doing this while alive, the pAI probably isn't dead yet.
- ..()
- if(paicard && (!client || stat == DEAD))
- ejectpai(0)
-
-/mob/living/simple_animal/bot/sentience_act()
- faction -= "silicon"
-
-/mob/living/simple_animal/bot/proc/activate_data_hud()
-//If a bot has its own HUD (for player bots), provide it.
- if(!data_hud_type)
- return
- var/datum/atom_hud/datahud = GLOB.huds[data_hud_type]
- datahud.add_hud_to(src)
+//Defines for bots are now found in code\__DEFINES\bots.dm
+
+// AI (i.e. game AI, not the AI player) controlled bots
+/mob/living/simple_animal/bot
+ icon = 'icons/mob/aibots.dmi'
+ layer = MOB_LAYER
+ gender = NEUTER
+ luminosity = 3
+ stop_automated_movement = 1
+ wander = 0
+ healable = 0
+ damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
+ atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
+ maxbodytemp = INFINITY
+ minbodytemp = 0
+ has_unlimited_silicon_privilege = 1
+ sentience_type = SENTIENCE_ARTIFICIAL
+ status_flags = NONE //no default canpush
+ verb_say = "states"
+ verb_ask = "queries"
+ verb_exclaim = "declares"
+ verb_yell = "alarms"
+ initial_language_holder = /datum/language_holder/synthetic
+ bubble_icon = "machine"
+
+ faction = list("neutral", "silicon" , "turret")
+
+ var/obj/machinery/bot_core/bot_core = null
+ var/bot_core_type = /obj/machinery/bot_core
+ var/list/users = list() //for dialog updates
+ var/window_id = "bot_control"
+ var/window_name = "Protobot 1.0" //Popup title
+ var/window_width = 0 //0 for default size
+ var/window_height = 0
+ var/obj/item/device/paicard/paicard // Inserted pai card.
+ var/allow_pai = 1 // Are we even allowed to insert a pai card.
+ var/bot_name
+
+ var/list/player_access = list() //Additonal access the bots gets when player controlled
+ var/emagged = 0
+ var/list/prev_access = list()
+ var/on = 1
+ var/open = 0//Maint panel
+ var/locked = 1
+ var/hacked = 0 //Used to differentiate between being hacked by silicons and emagged by humans.
+ var/text_hack = "" //Custom text returned to a silicon upon hacking a bot.
+ var/text_dehack = "" //Text shown when resetting a bots hacked status to normal.
+ var/text_dehack_fail = "" //Shown when a silicon tries to reset a bot emagged with the emag item, which cannot be reset.
+ var/declare_message = "" //What the bot will display to the HUD user.
+ var/frustration = 0 //Used by some bots for tracking failures to reach their target.
+ var/base_speed = 2 //The speed at which the bot moves, or the number of times it moves per process() tick.
+ var/turf/ai_waypoint //The end point of a bot's path, or the target location.
+ var/list/path = list() //List of turfs through which a bot 'steps' to reach the waypoint.
+ var/pathset = 0
+ var/list/ignore_list = list() //List of unreachable targets for an ignore-list enabled bot to ignore.
+ var/mode = BOT_IDLE //Standardizes the vars that indicate the bot is busy with its function.
+ var/tries = 0 //Number of times the bot tried and failed to move.
+ var/remote_disabled = 0 //If enabled, the AI cannot *Remotely* control a bot. It can still control it through cameras.
+ var/mob/living/silicon/ai/calling_ai //Links a bot to the AI calling it.
+ var/obj/item/device/radio/Radio //The bot's radio, for speaking to people.
+ var/radio_key = null //which channels can the bot listen to
+ var/radio_channel = "Common" //The bot's default radio channel
+ var/auto_patrol = 0// set to make bot automatically patrol
+ var/turf/patrol_target // this is turf to navigate to (location of beacon)
+ var/turf/summon_target // The turf of a user summoning a bot.
+ var/new_destination // pending new destination (waiting for beacon response)
+ var/destination // destination description tag
+ var/next_destination // the next destination in the patrol route
+ var/shuffle = FALSE // If we should shuffle our adjacency checking
+
+ var/blockcount = 0 //number of times retried a blocked path
+ var/awaiting_beacon = 0 // count of pticks awaiting a beacon response
+
+ var/nearest_beacon // the nearest beacon's tag
+ var/turf/nearest_beacon_loc // the nearest beacon's location
+
+ var/beacon_freq = 1445 // navigation beacon frequency
+ var/model = "" //The type of bot it is.
+ var/bot_type = 0 //The type of bot it is, for radio control.
+ var/data_hud_type = DATA_HUD_DIAGNOSTIC //The type of data HUD the bot uses. Diagnostic by default.
+ var/list/mode_name = list("In Pursuit","Preparing to Arrest", "Arresting", \
+ "Beginning Patrol", "Patrolling", "Summoned by PDA", \
+ "Cleaning", "Repairing", "Proceeding to work site", "Healing", \
+ "Proceeding to AI waypoint", "Navigating to Delivery Location", "Navigating to Home", \
+ "Waiting for clear path", "Calculating navigation path", "Pinging beacon network", "Unable to reach destination")
+ //This holds text for what the bot is mode doing, reported on the remote bot control interface.
+
+ hud_possible = list(DIAG_STAT_HUD, DIAG_BOT_HUD, DIAG_HUD) //Diagnostic HUD views
+
+/mob/living/simple_animal/bot/proc/get_mode()
+ if(client) //Player bots do not have modes, thus the override. Also an easy way for PDA users/AI to know when a bot is a player.
+ if(paicard)
+ return "pAI Controlled"
+ else
+ return "Autonomous"
+ else if(!on)
+ return "Inactive"
+ else if(!mode)
+ return "Idle"
+ else
+ return "[mode_name[mode]]"
+
+/mob/living/simple_animal/bot/proc/turn_on()
+ if(stat)
+ return 0
+ on = 1
+ set_light(initial(light_range))
+ update_icon()
+ diag_hud_set_botstat()
+ return 1
+
+/mob/living/simple_animal/bot/proc/turn_off()
+ on = 0
+ set_light(0)
+ bot_reset() //Resets an AI's call, should it exist.
+ update_icon()
+
+/mob/living/simple_animal/bot/Initialize()
+ ..()
+ access_card = new /obj/item/weapon/card/id(src)
+//This access is so bots can be immediately set to patrol and leave Robotics, instead of having to be let out first.
+ access_card.access += GLOB.access_robotics
+ set_custom_texts()
+ Radio = new/obj/item/device/radio(src)
+ if(radio_key)
+ Radio.keyslot = new radio_key
+ Radio.subspace_transmission = 1
+ Radio.canhear_range = 0 // anything greater will have the bot broadcast the channel as if it were saying it out loud.
+ Radio.recalculateChannels()
+
+ bot_core = new bot_core_type(src)
+
+ //Adds bot to the diagnostic HUD system
+ prepare_huds()
+ var/datum/atom_hud/data/diagnostic/diag_hud = GLOB.huds[DATA_HUD_DIAGNOSTIC]
+ diag_hud.add_to_hud(src)
+ diag_hud_set_bothealth()
+ diag_hud_set_botstat()
+ diag_hud_set_botmode()
+
+ //Gives a HUD view to player bots that use a HUD.
+ activate_data_hud()
+
+
+/mob/living/simple_animal/bot/update_canmove()
+ . = ..()
+ if(!on)
+ . = 0
+ canmove = .
+
+/mob/living/simple_animal/bot/Destroy()
+ if(paicard)
+ ejectpai()
+ qdel(Radio)
+ qdel(access_card)
+ qdel(bot_core)
+ return ..()
+
+/mob/living/simple_animal/bot/bee_friendly()
+ return 1
+
+/mob/living/simple_animal/bot/death(gibbed)
+ explode()
+ ..()
+
+/mob/living/simple_animal/bot/proc/explode()
+ qdel(src)
+
+/mob/living/simple_animal/bot/emag_act(mob/user)
+ if(locked) //First emag application unlocks the bot's interface. Apply a screwdriver to use the emag again.
+ locked = 0
+ emagged = 1
+ to_chat(user, "You bypass [src]'s controls.")
+ return
+ if(!locked && open) //Bot panel is unlocked by ID or emag, and the panel is screwed open. Ready for emagging.
+ emagged = 2
+ remote_disabled = 1 //Manually emagging the bot locks out the AI built in panel.
+ locked = 1 //Access denied forever!
+ bot_reset()
+ turn_on() //The bot automatically turns on when emagged, unless recently hit with EMP.
+ to_chat(src, "(#$*#$^^( OVERRIDE DETECTED")
+ add_logs(user, src, "emagged")
+ return
+ else //Bot is unlocked, but the maint panel has not been opened with a screwdriver yet.
+ to_chat(user, "You need to open maintenance panel first!")
+
+/mob/living/simple_animal/bot/examine(mob/user)
+ ..()
+ if(health < maxHealth)
+ if(health > maxHealth/3)
+ to_chat(user, "[src]'s parts look loose.")
+ else
+ to_chat(user, "[src]'s parts look very loose!")
+ else
+ to_chat(user, "[src] is in pristine condition.")
+
+/mob/living/simple_animal/bot/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
+ if(amount>0 && prob(10))
+ new /obj/effect/decal/cleanable/oil(loc)
+ . = ..()
+
+/mob/living/simple_animal/bot/updatehealth()
+ ..()
+ diag_hud_set_bothealth()
+
+/mob/living/simple_animal/bot/med_hud_set_health()
+ return //we use a different hud
+
+/mob/living/simple_animal/bot/med_hud_set_status()
+ return //we use a different hud
+
+/mob/living/simple_animal/bot/handle_automated_action() //Master process which handles code common across most bots.
+ set background = BACKGROUND_ENABLED
+ diag_hud_set_botmode()
+
+ if(!on || client)
+ return
+
+ switch(mode) //High-priority overrides are processed first. Bots can do nothing else while under direct command.
+ if(BOT_RESPONDING) //Called by the AI.
+ call_mode()
+ return
+ if(BOT_SUMMON) //Called by PDA
+ bot_summon()
+ return
+ return 1 //Successful completion. Used to prevent child process() continuing if this one is ended early.
+
+
+/mob/living/simple_animal/bot/attack_hand(mob/living/carbon/human/H)
+ if(H.a_intent == INTENT_HELP)
+ interact(H)
+ else
+ return ..()
+
+/mob/living/simple_animal/bot/attack_ai(mob/user)
+ if(!topic_denied(user))
+ interact(user)
+ else
+ to_chat(user, "[src]'s interface is not responding!")
+
+/mob/living/simple_animal/bot/interact(mob/user)
+ show_controls(user)
+
+/mob/living/simple_animal/bot/attackby(obj/item/weapon/W, mob/user, params)
+ if(istype(W, /obj/item/weapon/screwdriver))
+ if(!locked)
+ open = !open
+ to_chat(user, "The maintenance panel is now [open ? "opened" : "closed"].")
+ else
+ to_chat(user, "The maintenance panel is locked.")
+ else if(istype(W, /obj/item/weapon/card/id) || istype(W, /obj/item/device/pda))
+ if(bot_core.allowed(user) && !open && !emagged)
+ locked = !locked
+ to_chat(user, "Controls are now [locked ? "locked." : "unlocked."]")
+ else
+ if(emagged)
+ to_chat(user, "ERROR")
+ if(open)
+ to_chat(user, "Please close the access panel before locking it.")
+ else
+ to_chat(user, "Access denied.")
+ else if(istype(W, /obj/item/device/paicard))
+ insertpai(user, W)
+ else if(istype(W, /obj/item/weapon/hemostat) && paicard)
+ if(open)
+ to_chat(user, "Close the access panel before manipulating the personality slot!")
+ else
+ to_chat(user, "You attempt to pull [paicard] free...")
+ if(do_after(user, 30, target = src))
+ if (paicard)
+ user.visible_message("[user] uses [W] to pull [paicard] out of [bot_name]!","You pull [paicard] out of [bot_name] with [W].")
+ ejectpai(user)
+ else
+ user.changeNext_move(CLICK_CD_MELEE)
+ if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != INTENT_HARM)
+ if(health >= maxHealth)
+ to_chat(user, "[src] does not need a repair!")
+ return
+ if(!open)
+ to_chat(user, "Unable to repair with the maintenance panel closed!")
+ return
+ var/obj/item/weapon/weldingtool/WT = W
+ if(WT.remove_fuel(0, user))
+ adjustHealth(-10)
+ user.visible_message("[user] repairs [src]!","You repair [src].")
+ else
+ to_chat(user, "The welder must be on for this task!")
+ else
+ if(W.force) //if force is non-zero
+ do_sparks(5, TRUE, src)
+ ..()
+
+/mob/living/simple_animal/bot/bullet_act(obj/item/projectile/Proj)
+ if(Proj && (Proj.damage_type == BRUTE || Proj.damage_type == BURN))
+ if(prob(75) && Proj.damage > 0)
+ do_sparks(5, TRUE, src)
+ return ..()
+
+/mob/living/simple_animal/bot/emp_act(severity)
+ var/was_on = on
+ stat |= EMPED
+ new /obj/effect/overlay/temp/emp(loc)
+ if(paicard)
+ paicard.emp_act(severity)
+ src.visible_message("[paicard] is flies out of [bot_name]!","You are forcefully ejected from [bot_name]!")
+ ejectpai(0)
+ if(on)
+ turn_off()
+ spawn(severity*300)
+ stat &= ~EMPED
+ if(was_on)
+ turn_on()
+
+/mob/living/simple_animal/bot/proc/set_custom_texts() //Superclass for setting hack texts. Appears only if a set is not given to a bot locally.
+ text_hack = "You hack [name]."
+ text_dehack = "You reset [name]."
+ text_dehack_fail = "You fail to reset [name]."
+
+/mob/living/simple_animal/bot/proc/speak(message,channel) //Pass a message to have the bot say() it. Pass a frequency to say it on the radio.
+ if((!on) || (!message))
+ return
+ if(channel && Radio.channels[channel])// Use radio if we have channel key
+ Radio.talk_into(src, message, channel, get_spans(), get_default_language())
+ else
+ say(message)
+
+/mob/living/simple_animal/bot/get_spans()
+ return ..() | SPAN_ROBOT
+
+/mob/living/simple_animal/bot/radio(message, message_mode, list/spans, language)
+ . = ..()
+ if(. != 0)
+ return .
+
+ switch(message_mode)
+ if(MODE_HEADSET)
+ Radio.talk_into(src, message, , spans, language)
+ return REDUCE_RANGE
+
+ if(MODE_DEPARTMENT)
+ Radio.talk_into(src, message, message_mode, spans, language)
+ return REDUCE_RANGE
+
+ if(message_mode in GLOB.radiochannels)
+ Radio.talk_into(src, message, message_mode, spans, language)
+ return REDUCE_RANGE
+ return 0
+
+//Generalized behavior code, override where needed!
+
+/*
+scan() will search for a given type (such as turfs, human mobs, or objects) in the bot's view range, and return a single result.
+Arguments: The object type to be searched (such as "/mob/living/carbon/human"), the old scan result to be ignored, if one exists,
+and the view range, which defaults to 7 (full screen) if an override is not passed.
+If the bot maintains an ignore list, it is also checked here.
+
+Example usage: patient = scan(/mob/living/carbon/human, oldpatient, 1)
+The proc would return a human next to the bot to be set to the patient var.
+Pass the desired type path itself, declaring a temporary var beforehand is not required.
+*/
+/mob/living/simple_animal/bot/proc/scan(scan_type, old_target, scan_range = DEFAULT_SCAN_RANGE)
+ var/turf/T = get_turf(src)
+ if(!T)
+ return
+ var/list/adjacent = T.GetAtmosAdjacentTurfs(1)
+ if(shuffle) //If we were on the same tile as another bot, let's randomize our choices so we dont both go the same way
+ adjacent = shuffle(adjacent)
+ shuffle = FALSE
+ for(var/scan in adjacent)//Let's see if there's something right next to us first!
+ if(check_bot(scan)) //Is there another bot there? Then let's just skip it
+ continue
+ if(isturf(scan_type)) //If we're lookeing for a turf we can just run the checks directly!
+ var/final_result = checkscan(scan,scan_type,old_target)
+ if(final_result)
+ return final_result
+ else
+ var/turf/turfy = scan
+ for(var/deepscan in turfy.contents)//Check the contents since adjacent is turfs
+ var/final_result = checkscan(deepscan,scan_type,old_target)
+ if(final_result)
+ return final_result
+ for (var/scan in shuffle(view(scan_range, src))-adjacent) //Search for something in range!
+ var/final_result = checkscan(scan,scan_type,old_target)
+ if(final_result)
+ return final_result
+
+/mob/living/simple_animal/bot/proc/checkscan(scan, scan_type, old_target)
+ if(!istype(scan, scan_type)) //Check that the thing we found is the type we want!
+ return 0 //If not, keep searching!
+ if( (scan in ignore_list) || (scan == old_target) ) //Filter for blacklisted elements, usually unreachable or previously processed oness
+ return 0
+
+ var/scan_result = process_scan(scan) //Some bots may require additional processing when a result is selected.
+ if(scan_result)
+ return scan_result
+ else
+ return 0 //The current element failed assessment, move on to the next.
+ return
+
+/mob/living/simple_animal/bot/proc/check_bot(targ)
+ var/turf/T = get_turf(targ)
+ if(T)
+ for(var/C in T.contents)
+ if(istype(C,type) && (C != src)) //Is there another bot there already? If so, let's skip it so we dont all atack on top of eachother.
+ return 1 //Let's abort if we find a bot so we dont have to keep rechecking
+
+//When the scan finds a target, run bot specific processing to select it for the next step. Empty by default.
+/mob/living/simple_animal/bot/proc/process_scan(scan_target)
+ return scan_target
+
+
+/mob/living/simple_animal/bot/proc/add_to_ignore(subject)
+ if(ignore_list.len < 50) //This will help keep track of them, so the bot is always trying to reach a blocked spot.
+ ignore_list |= subject
+ else if(ignore_list.len >= subject) //If the list is full, insert newest, delete oldest.
+ ignore_list -= ignore_list[1]
+ ignore_list |= subject
+
+/*
+Movement proc for stepping a bot through a path generated through A-star.
+Pass a positive integer as an argument to override a bot's default speed.
+*/
+/mob/living/simple_animal/bot/proc/bot_move(dest, move_speed)
+
+ if(!dest || !path || path.len == 0) //A-star failed or a path/destination was not set.
+ path = list()
+ return 0
+ dest = get_turf(dest) //We must always compare turfs, so get the turf of the dest var if dest was originally something else.
+ var/turf/last_node = get_turf(path[path.len]) //This is the turf at the end of the path, it should be equal to dest.
+ if(get_turf(src) == dest) //We have arrived, no need to move again.
+ return 1
+ else if(dest != last_node) //The path should lead us to our given destination. If this is not true, we must stop.
+ path = list()
+ return 0
+ var/step_count = move_speed ? move_speed : base_speed //If a value is passed into move_speed, use that instead of the default speed var.
+
+ if(step_count >= 1 && tries < BOT_STEP_MAX_RETRIES)
+ for(var/step_number = 0, step_number < step_count,step_number++)
+ spawn(BOT_STEP_DELAY*step_number)
+ bot_step(dest)
+ else
+ return 0
+ return 1
+
+
+/mob/living/simple_animal/bot/proc/bot_step(dest) //Step,increase tries if failed
+ if(!path)
+ return 0
+ if(path.len > 1)
+ step_towards(src, path[1])
+ if(get_turf(src) == path[1]) //Successful move
+ path -= path[1]
+ tries = 0
+ else
+ tries++
+ return 0
+ else if(path.len == 1)
+ step_to(src, dest)
+ path = list()
+ return 1
+
+
+/mob/living/simple_animal/bot/proc/check_bot_access()
+ if(mode != BOT_SUMMON && mode != BOT_RESPONDING)
+ access_card.access = prev_access
+
+/mob/living/simple_animal/bot/proc/call_bot(caller, turf/waypoint, message=TRUE)
+ bot_reset() //Reset a bot before setting it to call mode.
+ var/area/end_area = get_area(waypoint)
+
+ if(client) //Player bots instead get a location command from the AI
+ to_chat(src, "Priority waypoint set by \icon[caller] [caller]. Proceed to [end_area.name]<\b>.")
+
+ //For giving the bot temporary all-access.
+ var/obj/item/weapon/card/id/all_access = new /obj/item/weapon/card/id
+ var/datum/job/captain/All = new/datum/job/captain
+ all_access.access = All.get_access()
+
+ path = get_path_to(src, waypoint, /turf/proc/Distance_cardinal, 0, 200, id=all_access)
+ calling_ai = caller //Link the AI to the bot!
+ ai_waypoint = waypoint
+
+ if(path && path.len) //Ensures that a valid path is calculated!
+ if(!on)
+ turn_on() //Saves the AI the hassle of having to activate a bot manually.
+ access_card = all_access //Give the bot all-access while under the AI's command.
+ if(message)
+ to_chat(calling_ai, "\icon[src] [name] called to [end_area.name]. [path.len-1] meters to destination.")
+ pathset = 1
+ mode = BOT_RESPONDING
+ tries = 0
+ else
+ if(message)
+ to_chat(calling_ai, "Failed to calculate a valid route. Ensure destination is clear of obstructions and within range.")
+ calling_ai = null
+ path = list()
+
+/mob/living/simple_animal/bot/proc/call_mode() //Handles preparing a bot for a call, as well as calling the move proc.
+//Handles the bot's movement during a call.
+ var/success = bot_move(ai_waypoint, 3)
+ if(!success)
+ if(calling_ai)
+ to_chat(calling_ai, "\icon[src] [get_turf(src) == ai_waypoint ? "[src] successfully arrived to waypoint." : "[src] failed to reach waypoint."]")
+ calling_ai = null
+ bot_reset()
+
+/mob/living/simple_animal/bot/proc/bot_reset()
+ if(calling_ai) //Simple notification to the AI if it called a bot. It will not know the cause or identity of the bot.
+ to_chat(calling_ai, "Call command to a bot has been reset.")
+ calling_ai = null
+ path = list()
+ summon_target = null
+ pathset = 0
+ access_card.access = prev_access
+ tries = 0
+ mode = BOT_IDLE
+ diag_hud_set_botstat()
+ diag_hud_set_botmode()
+
+
+
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//Patrol and summon code!
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+/mob/living/simple_animal/bot/proc/bot_patrol()
+ patrol_step()
+ spawn(5)
+ if(mode == BOT_PATROL)
+ patrol_step()
+ return
+
+/mob/living/simple_animal/bot/proc/start_patrol()
+
+ if(tries >= BOT_STEP_MAX_RETRIES) //Bot is trapped, so stop trying to patrol.
+ auto_patrol = 0
+ tries = 0
+ speak("Unable to start patrol.")
+
+ return
+
+ if(!auto_patrol) //A bot not set to patrol should not be patrolling.
+ mode = BOT_IDLE
+ return
+
+ if(patrol_target) // has patrol target
+ spawn(0)
+ calc_path() // Find a route to it
+ if(path.len == 0)
+ patrol_target = null
+ return
+ mode = BOT_PATROL
+ else // no patrol target, so need a new one
+ speak("Engaging patrol mode.")
+ find_patrol_target()
+ tries++
+ return
+
+// perform a single patrol step
+
+/mob/living/simple_animal/bot/proc/patrol_step()
+
+ if(client) // In use by player, don't actually move.
+ return
+
+ if(loc == patrol_target) // reached target
+ //Find the next beacon matching the target.
+ if(!get_next_patrol_target())
+ find_patrol_target() //If it fails, look for the nearest one instead.
+ return
+
+ else if(path.len > 0 && patrol_target) // valid path
+ var/turf/next = path[1]
+ if(next == loc)
+ path -= next
+ return
+
+
+ var/moved = bot_move(patrol_target)//step_towards(src, next) // attempt to move
+ if(!moved) //Couldn't proceed the next step of the path BOT_STEP_MAX_RETRIES times
+ spawn(2)
+ calc_path()
+ if(path.len == 0)
+ find_patrol_target()
+ tries = 0
+
+ else // no path, so calculate new one
+ mode = BOT_START_PATROL
+
+// finds the nearest beacon to self
+/mob/living/simple_animal/bot/proc/find_patrol_target()
+ nearest_beacon = null
+ new_destination = null
+ find_nearest_beacon()
+ if(nearest_beacon)
+ patrol_target = nearest_beacon_loc
+ destination = next_destination
+ else
+ auto_patrol = 0
+ mode = BOT_IDLE
+ speak("Disengaging patrol mode.")
+
+/mob/living/simple_animal/bot/proc/get_next_patrol_target()
+ // search the beacon list for the next target in the list.
+ for(var/obj/machinery/navbeacon/NB in GLOB.navbeacons["[z]"])
+ if(NB.location == next_destination) //Does the Beacon location text match the destination?
+ destination = new_destination //We now know the name of where we want to go.
+ patrol_target = NB.loc //Get its location and set it as the target.
+ next_destination = NB.codes["next_patrol"] //Also get the name of the next beacon in line.
+ return 1
+
+/mob/living/simple_animal/bot/proc/find_nearest_beacon()
+ for(var/obj/machinery/navbeacon/NB in GLOB.navbeacons["[z]"])
+ var/dist = get_dist(src, NB)
+ if(nearest_beacon) //Loop though the beacon net to find the true closest beacon.
+ //Ignore the beacon if were are located on it.
+ if(dist>1 && dist 1) //Begin the search, save this one for comparison on the next loop.
+ nearest_beacon = NB.location
+ nearest_beacon_loc = NB.loc
+ patrol_target = nearest_beacon_loc
+ destination = nearest_beacon
+
+//PDA control. Some bots, especially MULEs, may have more parameters.
+/mob/living/simple_animal/bot/proc/bot_control(command, mob/user, turf/user_turf, list/user_access = list())
+ if(!on || emagged == 2 || remote_disabled) //Emagged bots do not respect anyone's authority! Bots with their remote controls off cannot get commands.
+ return 1 //ACCESS DENIED
+ if(client)
+ bot_control_message(command,user,user_turf,user_access)
+ // process control input
+ switch(command)
+ if("patroloff")
+ bot_reset() //HOLD IT!!
+ auto_patrol = 0
+
+ if("patrolon")
+ auto_patrol = 1
+
+ if("summon")
+ bot_reset()
+ summon_target = user_turf
+ if(user_access.len != 0)
+ access_card.access = user_access + prev_access //Adds the user's access, if any.
+ mode = BOT_SUMMON
+ speak("Responding.", radio_channel)
+ calc_summon_path()
+
+ if("ejectpai")
+ ejectpairemote(user)
+ return
+
+//
+/mob/living/simple_animal/bot/proc/bot_control_message(command,user,user_turf,user_access)
+ switch(command)
+ if("patroloff")
+ to_chat(src, "STOP PATROL")
+ if("patrolon")
+ to_chat(src, "START PATROL")
+ if("summon")
+ var/area/a = get_area(user_turf)
+ to_chat(src, "PRIORITY ALERT:[user] in [a.name]!")
+ if("stop")
+ to_chat(src, "STOP!")
+
+ if("go")
+ to_chat(src, "GO!")
+
+ if("home")
+ to_chat(src, "RETURN HOME!")
+ if("ejectpai")
+ return
+ else
+ to_chat(src, "Unidentified control sequence recieved:[command]")
+
+/mob/living/simple_animal/bot/proc/bot_summon() // summoned to PDA
+ summon_step()
+
+// calculates a path to the current destination
+// given an optional turf to avoid
+/mob/living/simple_animal/bot/proc/calc_path(turf/avoid)
+ check_bot_access()
+ path = get_path_to(src, patrol_target, /turf/proc/Distance_cardinal, 0, 120, id=access_card, exclude=avoid)
+
+/mob/living/simple_animal/bot/proc/calc_summon_path(turf/avoid)
+ check_bot_access()
+ spawn()
+ path = get_path_to(src, summon_target, /turf/proc/Distance_cardinal, 0, 150, id=access_card, exclude=avoid)
+ if(!path.len) //Cannot reach target. Give up and announce the issue.
+ speak("Summon command failed, destination unreachable.",radio_channel)
+ bot_reset()
+
+/mob/living/simple_animal/bot/proc/summon_step()
+
+ if(client) // In use by player, don't actually move.
+ return
+
+ if(loc == summon_target) // Arrived to summon location.
+ bot_reset()
+ return
+
+ else if(path.len > 0 && summon_target) //Proper path acquired!
+ var/turf/next = path[1]
+ if(next == loc)
+ path -= next
+ return
+
+ var/moved = bot_move(summon_target, 3) // Move attempt
+ if(!moved)
+ spawn(2)
+ calc_summon_path()
+ tries = 0
+
+ else // no path, so calculate new one
+ calc_summon_path()
+
+/mob/living/simple_animal/bot/Bump(M as mob|obj) //Leave no door unopened!
+ . = ..()
+ if((istype(M, /obj/machinery/door/airlock) || istype(M, /obj/machinery/door/window)) && (!isnull(access_card)))
+ var/obj/machinery/door/D = M
+ if(D.check_access(access_card))
+ D.open()
+ frustration = 0
+
+/mob/living/simple_animal/bot/proc/show_controls(mob/M)
+ users |= M
+ var/dat = ""
+ dat = get_controls(M)
+ var/datum/browser/popup = new(M,window_id,window_name,350,600)
+ popup.set_content(dat)
+ popup.open(use_onclose = 0)
+ onclose(M,window_id,ref=src)
+ return
+
+/mob/living/simple_animal/bot/proc/update_controls()
+ for(var/mob/M in users)
+ show_controls(M)
+
+/mob/living/simple_animal/bot/proc/get_controls(mob/M)
+ return "PROTOBOT - NOT FOR USE"
+
+/mob/living/simple_animal/bot/Topic(href, href_list)
+ //No ..() to prevent strip panel showing up - Todo: make that saner
+ if(href_list["close"])// HUE HUE
+ if(usr in users)
+ users.Remove(usr)
+ return 1
+
+ if(topic_denied(usr))
+ to_chat(usr, "[src]'s interface is not responding!")
+ return 1
+ add_fingerprint(usr)
+
+ if((href_list["power"]) && (bot_core.allowed(usr) || !locked))
+ if(on)
+ turn_off()
+ else
+ turn_on()
+
+ switch(href_list["operation"])
+ if("patrol")
+ auto_patrol = !auto_patrol
+ bot_reset()
+ if("remote")
+ remote_disabled = !remote_disabled
+ if("hack")
+ if(emagged != 2)
+ emagged = 2
+ hacked = 1
+ locked = 1
+ to_chat(usr, "[text_hack]")
+ bot_reset()
+ else if(!hacked)
+ to_chat(usr, "[text_dehack_fail]")
+ else
+ emagged = 0
+ hacked = 0
+ to_chat(usr, "[text_dehack]")
+ bot_reset()
+ if("ejectpai")
+ if(paicard && (!locked || issilicon(usr) || IsAdminGhost(usr)))
+ to_chat(usr, "You eject [paicard] from [bot_name]")
+ ejectpai(usr)
+ update_controls()
+
+/mob/living/simple_animal/bot/proc/update_icon()
+ icon_state = "[initial(icon_state)][on]"
+
+// Machinery to simplify topic and access calls
+/obj/machinery/bot_core
+ use_power = 0
+ var/mob/living/simple_animal/bot/owner = null
+
+/obj/machinery/bot_core/Initialize()
+ ..()
+ owner = loc
+ if(!istype(owner))
+ qdel(src)
+
+/mob/living/simple_animal/bot/proc/topic_denied(mob/user) //Access check proc for bot topics! Remember to place in a bot's individual Topic if desired.
+ if(!user.canUseTopic(src))
+ return 1
+ // 0 for access, 1 for denied.
+ if(emagged == 2) //An emagged bot cannot be controlled by humans, silicons can if one hacked it.
+ if(!hacked) //Manually emagged by a human - access denied to all.
+ return 1
+ else if(!issilicon(user) && !IsAdminGhost(user)) //Bot is hacked, so only silicons and admins are allowed access.
+ return 1
+ return 0
+
+/mob/living/simple_animal/bot/proc/hack(mob/user)
+ var/hack
+ if(issilicon(user) || IsAdminGhost(user)) //Allows silicons or admins to toggle the emag status of a bot.
+ hack += "[emagged == 2 ? "Software compromised! Unit may exhibit dangerous or erratic behavior." : "Unit operating normally. Release safety lock?"]
"
+ hack += "Harm Prevention Safety System: [emagged ? "DANGER" : "Engaged"]
"
+ else if(!locked) //Humans with access can use this option to hide a bot from the AI's remote control panel and PDA control.
+ hack += "Remote network control radio: [remote_disabled ? "Disconnected" : "Connected"]
"
+ return hack
+
+/mob/living/simple_animal/bot/proc/showpai(mob/user)
+ var/eject = ""
+ if((!locked || issilicon(usr) || IsAdminGhost(usr)))
+ if(paicard || allow_pai)
+ eject += "Personality card status: "
+ if(paicard)
+ if(client)
+ eject += "Active"
+ else
+ eject += "Inactive"
+ else if(!allow_pai || key)
+ eject += "Unavailable"
+ else
+ eject += "Not inserted"
+ eject += "
"
+ eject += "
"
+ return eject
+
+/mob/living/simple_animal/bot/proc/insertpai(mob/user, obj/item/device/paicard/card)
+ if(paicard)
+ to_chat(user, "A [paicard] is already inserted!")
+ else if(allow_pai && !key)
+ if(!locked && !open)
+ if(card.pai && card.pai.mind)
+ if(!user.drop_item())
+ return
+ card.forceMove(src)
+ paicard = card
+ user.visible_message("[user] inserts [card] into [src]!","You insert [card] into [src].")
+ paicard.pai.mind.transfer_to(src)
+ to_chat(src, "You sense your form change as you are uploaded into [src].")
+ bot_name = name
+ name = paicard.pai.name
+ faction = user.faction.Copy()
+ add_logs(user, paicard.pai, "uploaded to [bot_name],")
+ return 1
+ else
+ to_chat(user, "[card] is inactive.")
+ else
+ to_chat(user, "The personality slot is locked.")
+ else
+ to_chat(user, "[src] is not compatible with [card]")
+
+/mob/living/simple_animal/bot/proc/ejectpai(mob/user = null, announce = 1)
+ if(paicard)
+ if(mind && paicard.pai)
+ mind.transfer_to(paicard.pai)
+ else if(paicard.pai)
+ paicard.pai.key = key
+ else
+ ghostize(0) // The pAI card that just got ejected was dead.
+ key = null
+ paicard.forceMove(loc)
+ if(user)
+ add_logs(user, paicard.pai, "ejected from [src.bot_name],")
+ else
+ add_logs(src, paicard.pai, "ejected")
+ if(announce)
+ to_chat(paicard.pai, "You feel your control fade as [paicard] ejects from [bot_name].")
+ paicard = null
+ name = bot_name
+ faction = initial(faction)
+
+/mob/living/simple_animal/bot/proc/ejectpairemote(mob/user)
+ if(bot_core.allowed(user) && paicard)
+ speak("Ejecting personality chip.", radio_channel)
+ ejectpai(user)
+
+/mob/living/simple_animal/bot/Login()
+ . = ..()
+ access_card.access += player_access
+ diag_hud_set_botmode()
+ activate_data_hud()
+
+/mob/living/simple_animal/bot/Logout()
+ . = ..()
+ bot_reset()
+
+/mob/living/simple_animal/bot/revive(full_heal = 0, admin_revive = 0)
+ if(..())
+ update_icon()
+ . = 1
+
+/mob/living/simple_animal/bot/ghost()
+ if(stat != DEAD) // Only ghost if we're doing this while alive, the pAI probably isn't dead yet.
+ ..()
+ if(paicard && (!client || stat == DEAD))
+ ejectpai(0)
+
+/mob/living/simple_animal/bot/sentience_act()
+ faction -= "silicon"
+
+/mob/living/simple_animal/bot/proc/activate_data_hud()
+//If a bot has its own HUD (for player bots), provide it.
+ if(!data_hud_type)
+ return
+ var/datum/atom_hud/datahud = GLOB.huds[data_hud_type]
+ datahud.add_hud_to(src)
diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm
index f384e70381..cba9e446ec 100644
--- a/code/modules/mob/living/simple_animal/bot/secbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/secbot.dm
@@ -1,421 +1,421 @@
-/mob/living/simple_animal/bot/secbot
- name = "\improper Securitron"
- desc = "A little security robot. He looks less than thrilled."
- icon = 'icons/mob/aibots.dmi'
- icon_state = "secbot0"
- density = 0
- anchored = 0
- health = 25
- maxHealth = 25
- damage_coeff = list(BRUTE = 0.5, BURN = 0.7, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
- pass_flags = PASSMOB
-
- radio_key = /obj/item/device/encryptionkey/secbot //AI Priv + Security
- radio_channel = "Security" //Security channel
- bot_type = SEC_BOT
- model = "Securitron"
- bot_core_type = /obj/machinery/bot_core/secbot
- var/baton_type = /obj/item/weapon/melee/baton
- window_id = "autosec"
- window_name = "Automatic Security Unit v1.6"
- allow_pai = 0
- data_hud_type = DATA_HUD_SECURITY_ADVANCED
-
- var/mob/living/carbon/target
- var/oldtarget_name
- var/threatlevel = 0
- var/target_lastloc //Loc of target when arrested.
- var/last_found //There's a delay
- var/declare_arrests = 1 //When making an arrest, should it notify everyone on the security channel?
- var/idcheck = 0 //If true, arrest people with no IDs
- var/weaponscheck = 0 //If true, arrest people for weapons if they lack access
- var/check_records = 1 //Does it check security records?
- var/arrest_type = 0 //If true, don't handcuff
-
-/mob/living/simple_animal/bot/secbot/beepsky
- name = "Officer Beep O'sky"
- desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
- idcheck = 0
- weaponscheck = 0
- auto_patrol = 1
-
-/mob/living/simple_animal/bot/secbot/beepsky/jr
- name = "Officer Pipsqueak"
- desc = "It's Officer Beep O'sky's smaller, just-as aggressive cousin, Pipsqueak."
-
-/mob/living/simple_animal/bot/secbot/beepsky/jr/Initialize()
- ..()
- resize = 0.8
- update_transform()
-
-
-/mob/living/simple_animal/bot/secbot/beepsky/explode()
- var/turf/Tsec = get_turf(src)
- new /obj/item/weapon/stock_parts/cell/potato(Tsec)
- var/obj/item/weapon/reagent_containers/food/drinks/drinkingglass/shotglass/S = new(Tsec)
- S.reagents.add_reagent("whiskey", 15)
- S.on_reagent_change()
- ..()
-
-/mob/living/simple_animal/bot/secbot/pingsky
- name = "Officer Pingsky"
- desc = "It's Officer Pingsky! Delegated to satellite guard duty for harbouring anti-human sentiment."
- radio_channel = "AI Private"
-
-/mob/living/simple_animal/bot/secbot/Initialize()
- ..()
- icon_state = "secbot[on]"
- spawn(3)
- var/datum/job/detective/J = new/datum/job/detective
- access_card.access += J.get_access()
- prev_access = access_card.access
-
- //SECHUD
- var/datum/atom_hud/secsensor = GLOB.huds[DATA_HUD_SECURITY_ADVANCED]
- secsensor.add_hud_to(src)
-
-/mob/living/simple_animal/bot/secbot/turn_on()
- ..()
- icon_state = "secbot[on]"
-
-/mob/living/simple_animal/bot/secbot/turn_off()
- ..()
- icon_state = "secbot[on]"
-
-/mob/living/simple_animal/bot/secbot/bot_reset()
- ..()
- target = null
- oldtarget_name = null
- anchored = 0
- walk_to(src,0)
- last_found = world.time
-
-/mob/living/simple_animal/bot/secbot/set_custom_texts()
-
- text_hack = "You overload [name]'s target identification system."
- text_dehack = "You reboot [name] and restore the target identification."
- text_dehack_fail = "[name] refuses to accept your authority!"
-
-/mob/living/simple_animal/bot/secbot/get_controls(mob/user)
- var/dat
- dat += hack(user)
- dat += showpai(user)
- dat += text({"
-Securitron v1.6 controls
-Status: []
-Behaviour controls are [locked ? "locked" : "unlocked"]
-Maintenance panel panel is [open ? "opened" : "closed"]"},
-
-"[on ? "On" : "Off"]" )
-
- if(!locked || issilicon(user) || IsAdminGhost(user))
- dat += text({"
-Arrest Unidentifiable Persons: []
-Arrest for Unauthorized Weapons: []
-Arrest for Warrant: []
-Operating Mode: []
-Report Arrests[]
-Auto Patrol: []"},
-
-"[idcheck ? "Yes" : "No"]",
-"[weaponscheck ? "Yes" : "No"]",
-"[check_records ? "Yes" : "No"]",
-"[arrest_type ? "Detain" : "Arrest"]",
-"[declare_arrests ? "Yes" : "No"]",
-"[auto_patrol ? "On" : "Off"]" )
-
- return dat
-
-/mob/living/simple_animal/bot/secbot/Topic(href, href_list)
- if(..())
- return 1
-
- switch(href_list["operation"])
- if("idcheck")
- idcheck = !idcheck
- update_controls()
- if("weaponscheck")
- weaponscheck = !weaponscheck
- update_controls()
- if("ignorerec")
- check_records = !check_records
- update_controls()
- if("switchmode")
- arrest_type = !arrest_type
- update_controls()
- if("declarearrests")
- declare_arrests = !declare_arrests
- update_controls()
-
-/mob/living/simple_animal/bot/secbot/proc/retaliate(mob/living/carbon/human/H)
- threatlevel = H.assess_threat(src)
- threatlevel += 6
- if(threatlevel >= 4)
- target = H
- mode = BOT_HUNT
-
-/mob/living/simple_animal/bot/secbot/attack_hand(mob/living/carbon/human/H)
- if((H.a_intent == INTENT_HARM) || (H.a_intent == INTENT_DISARM))
- retaliate(H)
-
- return ..()
-
-/mob/living/simple_animal/bot/secbot/attackby(obj/item/weapon/W, mob/user, params)
- ..()
- if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != INTENT_HARM) // Any intent but harm will heal, so we shouldn't get angry.
- return
- if(!istype(W, /obj/item/weapon/screwdriver) && (W.force) && (!target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
- retaliate(user)
-
-/mob/living/simple_animal/bot/secbot/emag_act(mob/user)
- ..()
- if(emagged == 2)
- if(user)
- to_chat(user, "You short out [src]'s target assessment circuits.")
- oldtarget_name = user.name
- audible_message("[src] buzzes oddly!")
- declare_arrests = 0
- icon_state = "secbot[on]"
-
-/mob/living/simple_animal/bot/secbot/bullet_act(obj/item/projectile/Proj)
- if(istype(Proj ,/obj/item/projectile/beam)||istype(Proj,/obj/item/projectile/bullet))
- if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE))
- if(!Proj.nodamage && Proj.damage < src.health)
- retaliate(Proj.firer)
- ..()
-
-
-/mob/living/simple_animal/bot/secbot/UnarmedAttack(atom/A)
- if(!on)
- return
- if(iscarbon(A))
- var/mob/living/carbon/C = A
- if(!C.stunned || arrest_type)
- stun_attack(A)
- else if(C.canBeHandcuffed() && !C.handcuffed)
- cuff(A)
- else
- ..()
-
-
-/mob/living/simple_animal/bot/secbot/hitby(atom/movable/AM, skipcatch = 0, hitpush = 1, blocked = 0)
- if(istype(AM, /obj/item))
- var/obj/item/I = AM
- if(I.throwforce < src.health && I.thrownby && ishuman(I.thrownby))
- var/mob/living/carbon/human/H = I.thrownby
- retaliate(H)
- ..()
-
-
-/mob/living/simple_animal/bot/secbot/proc/cuff(mob/living/carbon/C)
- mode = BOT_ARREST
- playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
- C.visible_message("[src] is trying to put zipties on [C]!",\
- "[src] is trying to put zipties on you!")
- spawn(60)
- if( !Adjacent(C) || !isturf(C.loc) ) //if he's in a closet or not adjacent, we cancel cuffing.
- return
- if(!C.handcuffed)
- C.handcuffed = new /obj/item/weapon/restraints/handcuffs/cable/zipties/used(C)
- C.update_handcuffed()
- playsound(loc, pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg'), 50, 0)
- back_to_idle()
-
-/mob/living/simple_animal/bot/secbot/proc/stun_attack(mob/living/carbon/C)
- playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
- icon_state = "secbot-c"
- spawn(2)
- icon_state = "secbot[on]"
- var/threat = 5
- if(ishuman(C))
- C.stuttering = 5
- C.Stun(5)
- C.Weaken(5)
- var/mob/living/carbon/human/H = C
- threat = H.assess_threat(src)
- else
- C.Weaken(5)
- C.stuttering = 5
- C.Stun(5)
- threat = C.assess_threat()
- add_logs(src,C,"stunned")
- if(declare_arrests)
- var/area/location = get_area(src)
- speak("[arrest_type ? "Detaining" : "Arresting"] level [threat] scumbag [C] in [location].", radio_channel)
- C.visible_message("[src] has stunned [C]!",\
- "[src] has stunned you!")
-
-/mob/living/simple_animal/bot/secbot/handle_automated_action()
- if(!..())
- return
-
- switch(mode)
-
- if(BOT_IDLE) // idle
-
- walk_to(src,0)
- look_for_perp() // see if any criminals are in range
- if(!mode && auto_patrol) // still idle, and set to patrol
- mode = BOT_START_PATROL // switch to patrol mode
-
- if(BOT_HUNT) // hunting for perp
-
- // if can't reach perp for long enough, go idle
- if(frustration >= 8)
- walk_to(src,0)
- back_to_idle()
- return
-
- if(target) // make sure target exists
- if(Adjacent(target) && isturf(target.loc)) // if right next to perp
- stun_attack(target)
-
- mode = BOT_PREP_ARREST
- anchored = 1
- target_lastloc = target.loc
- return
-
- else // not next to perp
- var/turf/olddist = get_dist(src, target)
- walk_to(src, target,1,4)
- if((get_dist(src, target)) >= (olddist))
- frustration++
- else
- frustration = 0
- else
- back_to_idle()
-
- if(BOT_PREP_ARREST) // preparing to arrest target
-
- // see if he got away. If he's no no longer adjacent or inside a closet or about to get up, we hunt again.
- if( !Adjacent(target) || !isturf(target.loc) || target.weakened < 2 )
- back_to_hunt()
- return
-
- if(iscarbon(target) && target.canBeHandcuffed())
- if(!arrest_type)
- if(!target.handcuffed) //he's not cuffed? Try to cuff him!
- cuff(target)
- else
- back_to_idle()
- return
- else
- back_to_idle()
- return
-
- if(BOT_ARREST)
- if(!target)
- anchored = 0
- mode = BOT_IDLE
- last_found = world.time
- frustration = 0
- return
-
- if(target.handcuffed) //no target or target cuffed? back to idle.
- back_to_idle()
- return
-
- if(!Adjacent(target) || !isturf(target.loc) || (target.loc != target_lastloc && target.weakened < 2)) //if he's changed loc and about to get up or not adjacent or got into a closet, we prep arrest again.
- back_to_hunt()
- return
- else //Try arresting again if the target escapes.
- mode = BOT_PREP_ARREST
- anchored = 0
-
- if(BOT_START_PATROL)
- look_for_perp()
- start_patrol()
-
- if(BOT_PATROL)
- look_for_perp()
- bot_patrol()
-
-
- return
-
-/mob/living/simple_animal/bot/secbot/proc/back_to_idle()
- anchored = 0
- mode = BOT_IDLE
- target = null
- last_found = world.time
- frustration = 0
- spawn(0)
- handle_automated_action() //ensure bot quickly responds
-
-/mob/living/simple_animal/bot/secbot/proc/back_to_hunt()
- anchored = 0
- frustration = 0
- mode = BOT_HUNT
- spawn(0)
- handle_automated_action() //ensure bot quickly responds
-// look for a criminal in view of the bot
-
-/mob/living/simple_animal/bot/secbot/proc/look_for_perp()
- anchored = 0
- for (var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal
- if((C.stat) || (C.handcuffed))
- continue
-
- if((C.name == oldtarget_name) && (world.time < last_found + 100))
- continue
-
- threatlevel = C.assess_threat(src)
-
- if(!threatlevel)
- continue
-
- else if(threatlevel >= 4)
- target = C
- oldtarget_name = C.name
- speak("Level [threatlevel] infraction alert!")
- playsound(loc, pick('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg'), 50, 0)
- visible_message("[src] points at [C.name]!")
- mode = BOT_HUNT
- spawn(0)
- handle_automated_action() // ensure bot quickly responds to a perp
- break
- else
- continue
-/mob/living/simple_animal/bot/secbot/proc/check_for_weapons(var/obj/item/slot_item)
- if(slot_item && slot_item.needs_permit)
- return 1
- return 0
-
-/mob/living/simple_animal/bot/secbot/explode()
-
- walk_to(src,0)
- visible_message("[src] blows apart!")
- var/turf/Tsec = get_turf(src)
-
- var/obj/item/weapon/secbot_assembly/Sa = new /obj/item/weapon/secbot_assembly(Tsec)
- Sa.build_step = 1
- Sa.add_overlay("hs_hole")
- Sa.created_name = name
- new /obj/item/device/assembly/prox_sensor(Tsec)
- new baton_type(Tsec)
-
- if(prob(50))
- new /obj/item/bodypart/l_arm/robot(Tsec)
-
- do_sparks(3, TRUE, src)
-
- new /obj/effect/decal/cleanable/oil(loc)
- ..()
-
-/mob/living/simple_animal/bot/secbot/attack_alien(var/mob/living/carbon/alien/user as mob)
- ..()
- if(!isalien(target))
- target = user
- mode = BOT_HUNT
-
-/mob/living/simple_animal/bot/secbot/Crossed(atom/movable/AM)
- if(ismob(AM) && target)
- var/mob/living/carbon/C = AM
- if(!istype(C) || !C || in_range(src, target))
- return
- knockOver(C)
- return
- ..()
-
-/obj/machinery/bot_core/secbot
- req_access = list(GLOB.access_security)
+/mob/living/simple_animal/bot/secbot
+ name = "\improper Securitron"
+ desc = "A little security robot. He looks less than thrilled."
+ icon = 'icons/mob/aibots.dmi'
+ icon_state = "secbot0"
+ density = 0
+ anchored = 0
+ health = 25
+ maxHealth = 25
+ damage_coeff = list(BRUTE = 0.5, BURN = 0.7, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
+ pass_flags = PASSMOB
+
+ radio_key = /obj/item/device/encryptionkey/secbot //AI Priv + Security
+ radio_channel = "Security" //Security channel
+ bot_type = SEC_BOT
+ model = "Securitron"
+ bot_core_type = /obj/machinery/bot_core/secbot
+ var/baton_type = /obj/item/weapon/melee/baton
+ window_id = "autosec"
+ window_name = "Automatic Security Unit v1.6"
+ allow_pai = 0
+ data_hud_type = DATA_HUD_SECURITY_ADVANCED
+
+ var/mob/living/carbon/target
+ var/oldtarget_name
+ var/threatlevel = 0
+ var/target_lastloc //Loc of target when arrested.
+ var/last_found //There's a delay
+ var/declare_arrests = 1 //When making an arrest, should it notify everyone on the security channel?
+ var/idcheck = 0 //If true, arrest people with no IDs
+ var/weaponscheck = 0 //If true, arrest people for weapons if they lack access
+ var/check_records = 1 //Does it check security records?
+ var/arrest_type = 0 //If true, don't handcuff
+
+/mob/living/simple_animal/bot/secbot/beepsky
+ name = "Officer Beep O'sky"
+ desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
+ idcheck = 0
+ weaponscheck = 0
+ auto_patrol = 1
+
+/mob/living/simple_animal/bot/secbot/beepsky/jr
+ name = "Officer Pipsqueak"
+ desc = "It's Officer Beep O'sky's smaller, just-as aggressive cousin, Pipsqueak."
+
+/mob/living/simple_animal/bot/secbot/beepsky/jr/Initialize()
+ ..()
+ resize = 0.8
+ update_transform()
+
+
+/mob/living/simple_animal/bot/secbot/beepsky/explode()
+ var/turf/Tsec = get_turf(src)
+ new /obj/item/weapon/stock_parts/cell/potato(Tsec)
+ var/obj/item/weapon/reagent_containers/food/drinks/drinkingglass/shotglass/S = new(Tsec)
+ S.reagents.add_reagent("whiskey", 15)
+ S.on_reagent_change()
+ ..()
+
+/mob/living/simple_animal/bot/secbot/pingsky
+ name = "Officer Pingsky"
+ desc = "It's Officer Pingsky! Delegated to satellite guard duty for harbouring anti-human sentiment."
+ radio_channel = "AI Private"
+
+/mob/living/simple_animal/bot/secbot/Initialize()
+ ..()
+ icon_state = "secbot[on]"
+ spawn(3)
+ var/datum/job/detective/J = new/datum/job/detective
+ access_card.access += J.get_access()
+ prev_access = access_card.access
+
+ //SECHUD
+ var/datum/atom_hud/secsensor = GLOB.huds[DATA_HUD_SECURITY_ADVANCED]
+ secsensor.add_hud_to(src)
+
+/mob/living/simple_animal/bot/secbot/turn_on()
+ ..()
+ icon_state = "secbot[on]"
+
+/mob/living/simple_animal/bot/secbot/turn_off()
+ ..()
+ icon_state = "secbot[on]"
+
+/mob/living/simple_animal/bot/secbot/bot_reset()
+ ..()
+ target = null
+ oldtarget_name = null
+ anchored = 0
+ walk_to(src,0)
+ last_found = world.time
+
+/mob/living/simple_animal/bot/secbot/set_custom_texts()
+
+ text_hack = "You overload [name]'s target identification system."
+ text_dehack = "You reboot [name] and restore the target identification."
+ text_dehack_fail = "[name] refuses to accept your authority!"
+
+/mob/living/simple_animal/bot/secbot/get_controls(mob/user)
+ var/dat
+ dat += hack(user)
+ dat += showpai(user)
+ dat += text({"
+Securitron v1.6 controls
+Status: []
+Behaviour controls are [locked ? "locked" : "unlocked"]
+Maintenance panel panel is [open ? "opened" : "closed"]"},
+
+"[on ? "On" : "Off"]" )
+
+ if(!locked || issilicon(user) || IsAdminGhost(user))
+ dat += text({"
+Arrest Unidentifiable Persons: []
+Arrest for Unauthorized Weapons: []
+Arrest for Warrant: []
+Operating Mode: []
+Report Arrests[]
+Auto Patrol: []"},
+
+"[idcheck ? "Yes" : "No"]",
+"[weaponscheck ? "Yes" : "No"]",
+"[check_records ? "Yes" : "No"]",
+"[arrest_type ? "Detain" : "Arrest"]",
+"[declare_arrests ? "Yes" : "No"]",
+"[auto_patrol ? "On" : "Off"]" )
+
+ return dat
+
+/mob/living/simple_animal/bot/secbot/Topic(href, href_list)
+ if(..())
+ return 1
+
+ switch(href_list["operation"])
+ if("idcheck")
+ idcheck = !idcheck
+ update_controls()
+ if("weaponscheck")
+ weaponscheck = !weaponscheck
+ update_controls()
+ if("ignorerec")
+ check_records = !check_records
+ update_controls()
+ if("switchmode")
+ arrest_type = !arrest_type
+ update_controls()
+ if("declarearrests")
+ declare_arrests = !declare_arrests
+ update_controls()
+
+/mob/living/simple_animal/bot/secbot/proc/retaliate(mob/living/carbon/human/H)
+ threatlevel = H.assess_threat(src)
+ threatlevel += 6
+ if(threatlevel >= 4)
+ target = H
+ mode = BOT_HUNT
+
+/mob/living/simple_animal/bot/secbot/attack_hand(mob/living/carbon/human/H)
+ if((H.a_intent == INTENT_HARM) || (H.a_intent == INTENT_DISARM))
+ retaliate(H)
+
+ return ..()
+
+/mob/living/simple_animal/bot/secbot/attackby(obj/item/weapon/W, mob/user, params)
+ ..()
+ if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent != INTENT_HARM) // Any intent but harm will heal, so we shouldn't get angry.
+ return
+ if(!istype(W, /obj/item/weapon/screwdriver) && (W.force) && (!target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
+ retaliate(user)
+
+/mob/living/simple_animal/bot/secbot/emag_act(mob/user)
+ ..()
+ if(emagged == 2)
+ if(user)
+ to_chat(user, "You short out [src]'s target assessment circuits.")
+ oldtarget_name = user.name
+ audible_message("[src] buzzes oddly!")
+ declare_arrests = 0
+ icon_state = "secbot[on]"
+
+/mob/living/simple_animal/bot/secbot/bullet_act(obj/item/projectile/Proj)
+ if(istype(Proj ,/obj/item/projectile/beam)||istype(Proj,/obj/item/projectile/bullet))
+ if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE))
+ if(!Proj.nodamage && Proj.damage < src.health)
+ retaliate(Proj.firer)
+ ..()
+
+
+/mob/living/simple_animal/bot/secbot/UnarmedAttack(atom/A)
+ if(!on)
+ return
+ if(iscarbon(A))
+ var/mob/living/carbon/C = A
+ if(!C.stunned || arrest_type)
+ stun_attack(A)
+ else if(C.canBeHandcuffed() && !C.handcuffed)
+ cuff(A)
+ else
+ ..()
+
+
+/mob/living/simple_animal/bot/secbot/hitby(atom/movable/AM, skipcatch = 0, hitpush = 1, blocked = 0)
+ if(istype(AM, /obj/item))
+ var/obj/item/I = AM
+ if(I.throwforce < src.health && I.thrownby && ishuman(I.thrownby))
+ var/mob/living/carbon/human/H = I.thrownby
+ retaliate(H)
+ ..()
+
+
+/mob/living/simple_animal/bot/secbot/proc/cuff(mob/living/carbon/C)
+ mode = BOT_ARREST
+ playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
+ C.visible_message("[src] is trying to put zipties on [C]!",\
+ "[src] is trying to put zipties on you!")
+ spawn(60)
+ if( !Adjacent(C) || !isturf(C.loc) ) //if he's in a closet or not adjacent, we cancel cuffing.
+ return
+ if(!C.handcuffed)
+ C.handcuffed = new /obj/item/weapon/restraints/handcuffs/cable/zipties/used(C)
+ C.update_handcuffed()
+ playsound(loc, pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg'), 50, 0)
+ back_to_idle()
+
+/mob/living/simple_animal/bot/secbot/proc/stun_attack(mob/living/carbon/C)
+ playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
+ icon_state = "secbot-c"
+ spawn(2)
+ icon_state = "secbot[on]"
+ var/threat = 5
+ if(ishuman(C))
+ C.stuttering = 5
+ C.Stun(5)
+ C.Weaken(5)
+ var/mob/living/carbon/human/H = C
+ threat = H.assess_threat(src)
+ else
+ C.Weaken(5)
+ C.stuttering = 5
+ C.Stun(5)
+ threat = C.assess_threat()
+ add_logs(src,C,"stunned")
+ if(declare_arrests)
+ var/area/location = get_area(src)
+ speak("[arrest_type ? "Detaining" : "Arresting"] level [threat] scumbag [C] in [location].", radio_channel)
+ C.visible_message("[src] has stunned [C]!",\
+ "[src] has stunned you!")
+
+/mob/living/simple_animal/bot/secbot/handle_automated_action()
+ if(!..())
+ return
+
+ switch(mode)
+
+ if(BOT_IDLE) // idle
+
+ walk_to(src,0)
+ look_for_perp() // see if any criminals are in range
+ if(!mode && auto_patrol) // still idle, and set to patrol
+ mode = BOT_START_PATROL // switch to patrol mode
+
+ if(BOT_HUNT) // hunting for perp
+
+ // if can't reach perp for long enough, go idle
+ if(frustration >= 8)
+ walk_to(src,0)
+ back_to_idle()
+ return
+
+ if(target) // make sure target exists
+ if(Adjacent(target) && isturf(target.loc)) // if right next to perp
+ stun_attack(target)
+
+ mode = BOT_PREP_ARREST
+ anchored = 1
+ target_lastloc = target.loc
+ return
+
+ else // not next to perp
+ var/turf/olddist = get_dist(src, target)
+ walk_to(src, target,1,4)
+ if((get_dist(src, target)) >= (olddist))
+ frustration++
+ else
+ frustration = 0
+ else
+ back_to_idle()
+
+ if(BOT_PREP_ARREST) // preparing to arrest target
+
+ // see if he got away. If he's no no longer adjacent or inside a closet or about to get up, we hunt again.
+ if( !Adjacent(target) || !isturf(target.loc) || target.weakened < 2 )
+ back_to_hunt()
+ return
+
+ if(iscarbon(target) && target.canBeHandcuffed())
+ if(!arrest_type)
+ if(!target.handcuffed) //he's not cuffed? Try to cuff him!
+ cuff(target)
+ else
+ back_to_idle()
+ return
+ else
+ back_to_idle()
+ return
+
+ if(BOT_ARREST)
+ if(!target)
+ anchored = 0
+ mode = BOT_IDLE
+ last_found = world.time
+ frustration = 0
+ return
+
+ if(target.handcuffed) //no target or target cuffed? back to idle.
+ back_to_idle()
+ return
+
+ if(!Adjacent(target) || !isturf(target.loc) || (target.loc != target_lastloc && target.weakened < 2)) //if he's changed loc and about to get up or not adjacent or got into a closet, we prep arrest again.
+ back_to_hunt()
+ return
+ else //Try arresting again if the target escapes.
+ mode = BOT_PREP_ARREST
+ anchored = 0
+
+ if(BOT_START_PATROL)
+ look_for_perp()
+ start_patrol()
+
+ if(BOT_PATROL)
+ look_for_perp()
+ bot_patrol()
+
+
+ return
+
+/mob/living/simple_animal/bot/secbot/proc/back_to_idle()
+ anchored = 0
+ mode = BOT_IDLE
+ target = null
+ last_found = world.time
+ frustration = 0
+ spawn(0)
+ handle_automated_action() //ensure bot quickly responds
+
+/mob/living/simple_animal/bot/secbot/proc/back_to_hunt()
+ anchored = 0
+ frustration = 0
+ mode = BOT_HUNT
+ spawn(0)
+ handle_automated_action() //ensure bot quickly responds
+// look for a criminal in view of the bot
+
+/mob/living/simple_animal/bot/secbot/proc/look_for_perp()
+ anchored = 0
+ for (var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal
+ if((C.stat) || (C.handcuffed))
+ continue
+
+ if((C.name == oldtarget_name) && (world.time < last_found + 100))
+ continue
+
+ threatlevel = C.assess_threat(src)
+
+ if(!threatlevel)
+ continue
+
+ else if(threatlevel >= 4)
+ target = C
+ oldtarget_name = C.name
+ speak("Level [threatlevel] infraction alert!")
+ playsound(loc, pick('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg'), 50, 0)
+ visible_message("[src] points at [C.name]!")
+ mode = BOT_HUNT
+ spawn(0)
+ handle_automated_action() // ensure bot quickly responds to a perp
+ break
+ else
+ continue
+/mob/living/simple_animal/bot/secbot/proc/check_for_weapons(var/obj/item/slot_item)
+ if(slot_item && slot_item.needs_permit)
+ return 1
+ return 0
+
+/mob/living/simple_animal/bot/secbot/explode()
+
+ walk_to(src,0)
+ visible_message("[src] blows apart!")
+ var/turf/Tsec = get_turf(src)
+
+ var/obj/item/weapon/secbot_assembly/Sa = new /obj/item/weapon/secbot_assembly(Tsec)
+ Sa.build_step = 1
+ Sa.add_overlay("hs_hole")
+ Sa.created_name = name
+ new /obj/item/device/assembly/prox_sensor(Tsec)
+ new baton_type(Tsec)
+
+ if(prob(50))
+ new /obj/item/bodypart/l_arm/robot(Tsec)
+
+ do_sparks(3, TRUE, src)
+
+ new /obj/effect/decal/cleanable/oil(loc)
+ ..()
+
+/mob/living/simple_animal/bot/secbot/attack_alien(var/mob/living/carbon/alien/user as mob)
+ ..()
+ if(!isalien(target))
+ target = user
+ mode = BOT_HUNT
+
+/mob/living/simple_animal/bot/secbot/Crossed(atom/movable/AM)
+ if(ismob(AM) && target)
+ var/mob/living/carbon/C = AM
+ if(!istype(C) || !C || in_range(src, target))
+ return
+ knockOver(C)
+ return
+ ..()
+
+/obj/machinery/bot_core/secbot
+ req_access = list(GLOB.access_security)
diff --git a/code/modules/mob/living/simple_animal/hostile/hivebot.dm b/code/modules/mob/living/simple_animal/hostile/hivebot.dm
index 266c9b1860..43290b860d 100644
--- a/code/modules/mob/living/simple_animal/hostile/hivebot.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hivebot.dm
@@ -1,57 +1,57 @@
-/obj/item/projectile/hivebotbullet
- damage = 10
- damage_type = BRUTE
-
-/mob/living/simple_animal/hostile/hivebot
- name = "hivebot"
- desc = "A small robot."
- icon = 'icons/mob/hivebot.dmi'
- icon_state = "basic"
- icon_living = "basic"
- icon_dead = "basic"
- gender = NEUTER
- health = 15
- maxHealth = 15
- healable = 0
- melee_damage_lower = 2
- melee_damage_upper = 3
- attacktext = "claws"
- attack_sound = 'sound/weapons/bladeslice.ogg'
- projectilesound = 'sound/weapons/Gunshot.ogg'
- projectiletype = /obj/item/projectile/hivebotbullet
- faction = list("hivebot")
- check_friendly_fire = 1
- atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
- minbodytemp = 0
- speak_emote = list("states")
- gold_core_spawnable = 1
- del_on_death = 1
- loot = list(/obj/effect/decal/cleanable/robot_debris)
-
-/mob/living/simple_animal/hostile/hivebot/Initialize()
- ..()
- deathmessage = "[src] blows apart!"
-
-/mob/living/simple_animal/hostile/hivebot/range
- name = "hivebot"
- desc = "A smallish robot, this one is armed!"
- ranged = 1
- retreat_distance = 5
- minimum_distance = 5
-
-/mob/living/simple_animal/hostile/hivebot/rapid
- ranged = 1
- rapid = 1
- retreat_distance = 5
- minimum_distance = 5
-
-/mob/living/simple_animal/hostile/hivebot/strong
- name = "strong hivebot"
- desc = "A robot, this one is armed and looks tough!"
- health = 80
- maxHealth = 80
- ranged = 1
-
-/mob/living/simple_animal/hostile/hivebot/death(gibbed)
- do_sparks(3, TRUE, src)
+/obj/item/projectile/hivebotbullet
+ damage = 10
+ damage_type = BRUTE
+
+/mob/living/simple_animal/hostile/hivebot
+ name = "hivebot"
+ desc = "A small robot."
+ icon = 'icons/mob/hivebot.dmi'
+ icon_state = "basic"
+ icon_living = "basic"
+ icon_dead = "basic"
+ gender = NEUTER
+ health = 15
+ maxHealth = 15
+ healable = 0
+ melee_damage_lower = 2
+ melee_damage_upper = 3
+ attacktext = "claws"
+ attack_sound = 'sound/weapons/bladeslice.ogg'
+ projectilesound = 'sound/weapons/Gunshot.ogg'
+ projectiletype = /obj/item/projectile/hivebotbullet
+ faction = list("hivebot")
+ check_friendly_fire = 1
+ atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
+ minbodytemp = 0
+ speak_emote = list("states")
+ gold_core_spawnable = 1
+ del_on_death = 1
+ loot = list(/obj/effect/decal/cleanable/robot_debris)
+
+/mob/living/simple_animal/hostile/hivebot/Initialize()
+ ..()
+ deathmessage = "[src] blows apart!"
+
+/mob/living/simple_animal/hostile/hivebot/range
+ name = "hivebot"
+ desc = "A smallish robot, this one is armed!"
+ ranged = 1
+ retreat_distance = 5
+ minimum_distance = 5
+
+/mob/living/simple_animal/hostile/hivebot/rapid
+ ranged = 1
+ rapid = 1
+ retreat_distance = 5
+ minimum_distance = 5
+
+/mob/living/simple_animal/hostile/hivebot/strong
+ name = "strong hivebot"
+ desc = "A robot, this one is armed and looks tough!"
+ health = 80
+ maxHealth = 80
+ ranged = 1
+
+/mob/living/simple_animal/hostile/hivebot/death(gibbed)
+ do_sparks(3, TRUE, src)
..(1)
\ No newline at end of file
diff --git a/code/modules/projectiles/ammunition/energy.dm b/code/modules/projectiles/ammunition/energy.dm
index b78572cfcd..bf695cffed 100644
--- a/code/modules/projectiles/ammunition/energy.dm
+++ b/code/modules/projectiles/ammunition/energy.dm
@@ -1,236 +1,236 @@
-/obj/item/ammo_casing/energy
- name = "energy weapon lens"
- desc = "The part of the gun that makes the laser go pew"
- caliber = "energy"
- projectile_type = /obj/item/projectile/energy
- var/e_cost = 100 //The amount of energy a cell needs to expend to create this shot.
- var/select_name = "energy"
- fire_sound = 'sound/weapons/Laser.ogg'
- firing_effect_type = /obj/effect/overlay/temp/dir_setting/firing_effect/energy
-
-/obj/item/ammo_casing/energy/chameleon
- e_cost = 0
- var/list/projectile_vars = list()
-
-/obj/item/ammo_casing/energy/chameleon/ready_proj()
- . = ..()
- if(!BB)
- newshot()
- for(var/V in projectile_vars)
- if(BB.vars[V])
- BB.vars[V] = projectile_vars[V]
-
-/obj/item/ammo_casing/energy/laser
- projectile_type = /obj/item/projectile/beam/laser
- select_name = "kill"
-
-/obj/item/ammo_casing/energy/lasergun
- projectile_type = /obj/item/projectile/beam/laser
- e_cost = 83
- select_name = "kill"
-
-/obj/item/ammo_casing/energy/laser/hos
- e_cost = 100
-
-/obj/item/ammo_casing/energy/laser/practice
- projectile_type = /obj/item/projectile/beam/practice
- select_name = "practice"
-
-/obj/item/ammo_casing/energy/laser/scatter
- projectile_type = /obj/item/projectile/beam/scatter
- pellets = 5
- variance = 25
- select_name = "scatter"
-
-/obj/item/ammo_casing/energy/laser/scatter/disabler
- projectile_type = /obj/item/projectile/beam/disabler
- pellets = 3
- variance = 15
-
-/obj/item/ammo_casing/energy/laser/heavy
- projectile_type = /obj/item/projectile/beam/laser/heavylaser
- select_name = "anti-vehicle"
- fire_sound = 'sound/weapons/lasercannonfire.ogg'
-
-/obj/item/ammo_casing/energy/laser/pulse
- projectile_type = /obj/item/projectile/beam/pulse
- e_cost = 200
- select_name = "DESTROY"
- fire_sound = 'sound/weapons/pulse.ogg'
-
-/obj/item/ammo_casing/energy/laser/bluetag
- projectile_type = /obj/item/projectile/beam/lasertag/bluetag
- select_name = "bluetag"
-
-/obj/item/ammo_casing/energy/laser/redtag
- projectile_type = /obj/item/projectile/beam/lasertag/redtag
- select_name = "redtag"
-
-/obj/item/ammo_casing/energy/xray
- projectile_type = /obj/item/projectile/beam/xray
- e_cost = 50
- fire_sound = 'sound/weapons/laser3.ogg'
-
-/obj/item/ammo_casing/energy/electrode
- projectile_type = /obj/item/projectile/energy/electrode
- select_name = "stun"
- fire_sound = 'sound/weapons/taser.ogg'
- e_cost = 200
-
-/obj/item/ammo_casing/energy/electrode/gun
- fire_sound = 'sound/weapons/gunshot.ogg'
- e_cost = 100
-
-/obj/item/ammo_casing/energy/electrode/hos
- e_cost = 200
-
-/obj/item/ammo_casing/energy/ion
- projectile_type = /obj/item/projectile/ion
- select_name = "ion"
- fire_sound = 'sound/weapons/IonRifle.ogg'
-
-/obj/item/ammo_casing/energy/declone
- projectile_type = /obj/item/projectile/energy/declone
- select_name = "declone"
- fire_sound = 'sound/weapons/pulse3.ogg'
-
-/obj/item/ammo_casing/energy/mindflayer
- projectile_type = /obj/item/projectile/beam/mindflayer
- select_name = "MINDFUCK"
- fire_sound = 'sound/weapons/Laser.ogg'
-
-/obj/item/ammo_casing/energy/flora
- fire_sound = 'sound/effects/stealthoff.ogg'
-
-/obj/item/ammo_casing/energy/flora/yield
- projectile_type = /obj/item/projectile/energy/florayield
- select_name = "yield"
-
-/obj/item/ammo_casing/energy/flora/mut
- projectile_type = /obj/item/projectile/energy/floramut
- select_name = "mutation"
-
-/obj/item/ammo_casing/energy/temp
- projectile_type = /obj/item/projectile/temp
- select_name = "freeze"
- e_cost = 250
- fire_sound = 'sound/weapons/pulse3.ogg'
-
-/obj/item/ammo_casing/energy/temp/hot
- projectile_type = /obj/item/projectile/temp/hot
- select_name = "bake"
-
-/obj/item/ammo_casing/energy/meteor
- projectile_type = /obj/item/projectile/meteor
- select_name = "goddamn meteor"
-
-/obj/item/ammo_casing/energy/disabler
- projectile_type = /obj/item/projectile/beam/disabler
- select_name = "disable"
- e_cost = 50
- fire_sound = 'sound/weapons/taser2.ogg'
-
-/obj/item/ammo_casing/energy/plasma
- projectile_type = /obj/item/projectile/plasma
- select_name = "plasma burst"
- fire_sound = 'sound/weapons/plasma_cutter.ogg'
- delay = 15
- e_cost = 25
-
-/obj/item/ammo_casing/energy/plasma/adv
- projectile_type = /obj/item/projectile/plasma/adv
- delay = 10
- e_cost = 10
-
-/obj/item/ammo_casing/energy/wormhole
- projectile_type = /obj/item/projectile/beam/wormhole
- e_cost = 0
- fire_sound = 'sound/weapons/pulse3.ogg'
- var/obj/item/weapon/gun/energy/wormhole_projector/gun = null
- select_name = "blue"
-
-/obj/item/ammo_casing/energy/wormhole/orange
- projectile_type = /obj/item/projectile/beam/wormhole/orange
- select_name = "orange"
-
-/obj/item/ammo_casing/energy/bolt
- projectile_type = /obj/item/projectile/energy/bolt
- select_name = "bolt"
- e_cost = 500
- fire_sound = 'sound/weapons/Genhit.ogg'
-
-/obj/item/ammo_casing/energy/bolt/halloween
- projectile_type = /obj/item/projectile/energy/bolt/halloween
-
-/obj/item/ammo_casing/energy/bolt/large
- projectile_type = /obj/item/projectile/energy/bolt/large
- select_name = "heavy bolt"
-
-/obj/item/ammo_casing/energy/net
- projectile_type = /obj/item/projectile/energy/net
- select_name = "netting"
- pellets = 6
- variance = 40
-
-/obj/item/ammo_casing/energy/trap
- projectile_type = /obj/item/projectile/energy/trap
- select_name = "snare"
-
-/obj/item/ammo_casing/energy/instakill
- projectile_type = /obj/item/projectile/beam/instakill
- e_cost = 0
- select_name = "DESTROY"
-
-/obj/item/ammo_casing/energy/instakill/blue
- projectile_type = /obj/item/projectile/beam/instakill/blue
-
-/obj/item/ammo_casing/energy/instakill/red
- projectile_type = /obj/item/projectile/beam/instakill/red
-
-/obj/item/ammo_casing/energy/tesla_revolver
- fire_sound = 'sound/magic/lightningbolt.ogg'
- e_cost = 200
- select_name = "stun"
- projectile_type = /obj/item/projectile/energy/tesla/revolver
-
-/obj/item/ammo_casing/energy/gravityrepulse
- projectile_type = /obj/item/projectile/gravityrepulse
- e_cost = 0
- fire_sound = 'sound/weapons/wave.ogg'
- select_name = "repulse"
- delay = 50
- var/obj/item/weapon/gun/energy/gravity_gun/gun = null
-
-/obj/item/ammo_casing/energy/gravityrepulse/New(var/obj/item/weapon/gun/energy/gravity_gun/G)
- gun = G
-
-/obj/item/ammo_casing/energy/gravityattract
- projectile_type = /obj/item/projectile/gravityattract
- e_cost = 0
- fire_sound = 'sound/weapons/wave.ogg'
- select_name = "attract"
- delay = 50
- var/obj/item/weapon/gun/energy/gravity_gun/gun = null
-
-
-/obj/item/ammo_casing/energy/gravityattract/New(var/obj/item/weapon/gun/energy/gravity_gun/G)
- gun = G
-
-/obj/item/ammo_casing/energy/gravitychaos
- projectile_type = /obj/item/projectile/gravitychaos
- e_cost = 0
- fire_sound = 'sound/weapons/wave.ogg'
- select_name = "chaos"
- delay = 50
- var/obj/item/weapon/gun/energy/gravity_gun/gun = null
-
-/obj/item/ammo_casing/energy/gravitychaos/New(var/obj/item/weapon/gun/energy/gravity_gun/G)
- gun = G
-
-/obj/item/ammo_casing/energy/plasma
- projectile_type = /obj/item/projectile/plasma
- select_name = "plasma burst"
- fire_sound = 'sound/weapons/pulse.ogg'
-
-/obj/item/ammo_casing/energy/plasma/adv
- projectile_type = /obj/item/projectile/plasma/adv
+/obj/item/ammo_casing/energy
+ name = "energy weapon lens"
+ desc = "The part of the gun that makes the laser go pew"
+ caliber = "energy"
+ projectile_type = /obj/item/projectile/energy
+ var/e_cost = 100 //The amount of energy a cell needs to expend to create this shot.
+ var/select_name = "energy"
+ fire_sound = 'sound/weapons/Laser.ogg'
+ firing_effect_type = /obj/effect/overlay/temp/dir_setting/firing_effect/energy
+
+/obj/item/ammo_casing/energy/chameleon
+ e_cost = 0
+ var/list/projectile_vars = list()
+
+/obj/item/ammo_casing/energy/chameleon/ready_proj()
+ . = ..()
+ if(!BB)
+ newshot()
+ for(var/V in projectile_vars)
+ if(BB.vars[V])
+ BB.vars[V] = projectile_vars[V]
+
+/obj/item/ammo_casing/energy/laser
+ projectile_type = /obj/item/projectile/beam/laser
+ select_name = "kill"
+
+/obj/item/ammo_casing/energy/lasergun
+ projectile_type = /obj/item/projectile/beam/laser
+ e_cost = 83
+ select_name = "kill"
+
+/obj/item/ammo_casing/energy/laser/hos
+ e_cost = 100
+
+/obj/item/ammo_casing/energy/laser/practice
+ projectile_type = /obj/item/projectile/beam/practice
+ select_name = "practice"
+
+/obj/item/ammo_casing/energy/laser/scatter
+ projectile_type = /obj/item/projectile/beam/scatter
+ pellets = 5
+ variance = 25
+ select_name = "scatter"
+
+/obj/item/ammo_casing/energy/laser/scatter/disabler
+ projectile_type = /obj/item/projectile/beam/disabler
+ pellets = 3
+ variance = 15
+
+/obj/item/ammo_casing/energy/laser/heavy
+ projectile_type = /obj/item/projectile/beam/laser/heavylaser
+ select_name = "anti-vehicle"
+ fire_sound = 'sound/weapons/lasercannonfire.ogg'
+
+/obj/item/ammo_casing/energy/laser/pulse
+ projectile_type = /obj/item/projectile/beam/pulse
+ e_cost = 200
+ select_name = "DESTROY"
+ fire_sound = 'sound/weapons/pulse.ogg'
+
+/obj/item/ammo_casing/energy/laser/bluetag
+ projectile_type = /obj/item/projectile/beam/lasertag/bluetag
+ select_name = "bluetag"
+
+/obj/item/ammo_casing/energy/laser/redtag
+ projectile_type = /obj/item/projectile/beam/lasertag/redtag
+ select_name = "redtag"
+
+/obj/item/ammo_casing/energy/xray
+ projectile_type = /obj/item/projectile/beam/xray
+ e_cost = 50
+ fire_sound = 'sound/weapons/laser3.ogg'
+
+/obj/item/ammo_casing/energy/electrode
+ projectile_type = /obj/item/projectile/energy/electrode
+ select_name = "stun"
+ fire_sound = 'sound/weapons/taser.ogg'
+ e_cost = 200
+
+/obj/item/ammo_casing/energy/electrode/gun
+ fire_sound = 'sound/weapons/gunshot.ogg'
+ e_cost = 100
+
+/obj/item/ammo_casing/energy/electrode/hos
+ e_cost = 200
+
+/obj/item/ammo_casing/energy/ion
+ projectile_type = /obj/item/projectile/ion
+ select_name = "ion"
+ fire_sound = 'sound/weapons/IonRifle.ogg'
+
+/obj/item/ammo_casing/energy/declone
+ projectile_type = /obj/item/projectile/energy/declone
+ select_name = "declone"
+ fire_sound = 'sound/weapons/pulse3.ogg'
+
+/obj/item/ammo_casing/energy/mindflayer
+ projectile_type = /obj/item/projectile/beam/mindflayer
+ select_name = "MINDFUCK"
+ fire_sound = 'sound/weapons/Laser.ogg'
+
+/obj/item/ammo_casing/energy/flora
+ fire_sound = 'sound/effects/stealthoff.ogg'
+
+/obj/item/ammo_casing/energy/flora/yield
+ projectile_type = /obj/item/projectile/energy/florayield
+ select_name = "yield"
+
+/obj/item/ammo_casing/energy/flora/mut
+ projectile_type = /obj/item/projectile/energy/floramut
+ select_name = "mutation"
+
+/obj/item/ammo_casing/energy/temp
+ projectile_type = /obj/item/projectile/temp
+ select_name = "freeze"
+ e_cost = 250
+ fire_sound = 'sound/weapons/pulse3.ogg'
+
+/obj/item/ammo_casing/energy/temp/hot
+ projectile_type = /obj/item/projectile/temp/hot
+ select_name = "bake"
+
+/obj/item/ammo_casing/energy/meteor
+ projectile_type = /obj/item/projectile/meteor
+ select_name = "goddamn meteor"
+
+/obj/item/ammo_casing/energy/disabler
+ projectile_type = /obj/item/projectile/beam/disabler
+ select_name = "disable"
+ e_cost = 50
+ fire_sound = 'sound/weapons/taser2.ogg'
+
+/obj/item/ammo_casing/energy/plasma
+ projectile_type = /obj/item/projectile/plasma
+ select_name = "plasma burst"
+ fire_sound = 'sound/weapons/plasma_cutter.ogg'
+ delay = 15
+ e_cost = 25
+
+/obj/item/ammo_casing/energy/plasma/adv
+ projectile_type = /obj/item/projectile/plasma/adv
+ delay = 10
+ e_cost = 10
+
+/obj/item/ammo_casing/energy/wormhole
+ projectile_type = /obj/item/projectile/beam/wormhole
+ e_cost = 0
+ fire_sound = 'sound/weapons/pulse3.ogg'
+ var/obj/item/weapon/gun/energy/wormhole_projector/gun = null
+ select_name = "blue"
+
+/obj/item/ammo_casing/energy/wormhole/orange
+ projectile_type = /obj/item/projectile/beam/wormhole/orange
+ select_name = "orange"
+
+/obj/item/ammo_casing/energy/bolt
+ projectile_type = /obj/item/projectile/energy/bolt
+ select_name = "bolt"
+ e_cost = 500
+ fire_sound = 'sound/weapons/Genhit.ogg'
+
+/obj/item/ammo_casing/energy/bolt/halloween
+ projectile_type = /obj/item/projectile/energy/bolt/halloween
+
+/obj/item/ammo_casing/energy/bolt/large
+ projectile_type = /obj/item/projectile/energy/bolt/large
+ select_name = "heavy bolt"
+
+/obj/item/ammo_casing/energy/net
+ projectile_type = /obj/item/projectile/energy/net
+ select_name = "netting"
+ pellets = 6
+ variance = 40
+
+/obj/item/ammo_casing/energy/trap
+ projectile_type = /obj/item/projectile/energy/trap
+ select_name = "snare"
+
+/obj/item/ammo_casing/energy/instakill
+ projectile_type = /obj/item/projectile/beam/instakill
+ e_cost = 0
+ select_name = "DESTROY"
+
+/obj/item/ammo_casing/energy/instakill/blue
+ projectile_type = /obj/item/projectile/beam/instakill/blue
+
+/obj/item/ammo_casing/energy/instakill/red
+ projectile_type = /obj/item/projectile/beam/instakill/red
+
+/obj/item/ammo_casing/energy/tesla_revolver
+ fire_sound = 'sound/magic/lightningbolt.ogg'
+ e_cost = 200
+ select_name = "stun"
+ projectile_type = /obj/item/projectile/energy/tesla/revolver
+
+/obj/item/ammo_casing/energy/gravityrepulse
+ projectile_type = /obj/item/projectile/gravityrepulse
+ e_cost = 0
+ fire_sound = 'sound/weapons/wave.ogg'
+ select_name = "repulse"
+ delay = 50
+ var/obj/item/weapon/gun/energy/gravity_gun/gun = null
+
+/obj/item/ammo_casing/energy/gravityrepulse/New(var/obj/item/weapon/gun/energy/gravity_gun/G)
+ gun = G
+
+/obj/item/ammo_casing/energy/gravityattract
+ projectile_type = /obj/item/projectile/gravityattract
+ e_cost = 0
+ fire_sound = 'sound/weapons/wave.ogg'
+ select_name = "attract"
+ delay = 50
+ var/obj/item/weapon/gun/energy/gravity_gun/gun = null
+
+
+/obj/item/ammo_casing/energy/gravityattract/New(var/obj/item/weapon/gun/energy/gravity_gun/G)
+ gun = G
+
+/obj/item/ammo_casing/energy/gravitychaos
+ projectile_type = /obj/item/projectile/gravitychaos
+ e_cost = 0
+ fire_sound = 'sound/weapons/wave.ogg'
+ select_name = "chaos"
+ delay = 50
+ var/obj/item/weapon/gun/energy/gravity_gun/gun = null
+
+/obj/item/ammo_casing/energy/gravitychaos/New(var/obj/item/weapon/gun/energy/gravity_gun/G)
+ gun = G
+
+/obj/item/ammo_casing/energy/plasma
+ projectile_type = /obj/item/projectile/plasma
+ select_name = "plasma burst"
+ fire_sound = 'sound/weapons/pulse.ogg'
+
+/obj/item/ammo_casing/energy/plasma/adv
+ projectile_type = /obj/item/projectile/plasma/adv
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 0eedcd5bc8..3dedaa9ae1 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -1,313 +1,313 @@
-/obj/item/projectile
- name = "projectile"
- icon = 'icons/obj/projectiles.dmi'
- icon_state = "bullet"
- density = 0
- anchored = 1
- flags = ABSTRACT
- pass_flags = PASSTABLE
- mouse_opacity = 0
- hitsound = 'sound/weapons/pierce.ogg'
- var/hitsound_wall = ""
-
- resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
- var/def_zone = "" //Aiming at
- var/mob/firer = null//Who shot it
- var/suppressed = 0 //Attack message
- var/yo = null
- var/xo = null
- var/current = null
- var/atom/original = null // the original target clicked
- var/turf/starting = null // the projectile's starting turf
- var/list/permutated = list() // we've passed through these atoms, don't try to hit them again
- var/paused = FALSE //for suspending the projectile midair
- var/p_x = 16
- var/p_y = 16 // the pixel location of the tile that the player clicked. Default is the center
- var/speed = 0.8 //Amount of deciseconds it takes for projectile to travel
- var/Angle = 0
- var/spread = 0 //amount (in degrees) of projectile spread
- var/legacy = 0 //legacy projectile system
- animate_movement = 0 //Use SLIDE_STEPS in conjunction with legacy
-
- var/damage = 10
- var/damage_type = BRUTE //BRUTE, BURN, TOX, OXY, CLONE are the only things that should be in here
- var/nodamage = 0 //Determines if the projectile will skip any damage inflictions
- var/flag = "bullet" //Defines what armor to use when it hits things. Must be set to bullet, laser, energy,or bomb
- var/projectile_type = /obj/item/projectile
- var/range = 50 //This will de-increment every step. When 0, it will delete the projectile.
- //Effects
- var/stun = 0
- var/weaken = 0
- var/paralyze = 0
- var/irradiate = 0
- var/stutter = 0
- var/slur = 0
- var/eyeblur = 0
- var/drowsy = 0
- var/stamina = 0
- var/jitter = 0
- var/forcedodge = 0 //to pass through everything
- var/dismemberment = 0 //The higher the number, the greater the bonus to dismembering. 0 will not dismember at all.
- var/impact_effect_type //what type of impact effect to show when hitting something
- var/log_override = FALSE //is this type spammed enough to not log? (KAs)
-
-/obj/item/projectile/New()
- permutated = list()
- return ..()
-
-/obj/item/projectile/proc/Range()
- range--
- if(range <= 0 && loc)
- on_range()
-
-/obj/item/projectile/proc/on_range() //if we want there to be effects when they reach the end of their range
- qdel(src)
-
-//to get the correct limb (if any) for the projectile hit message
-/mob/living/proc/check_limb_hit(hit_zone)
- if(has_limbs)
- return hit_zone
-
-/mob/living/carbon/check_limb_hit(hit_zone)
- if(get_bodypart(hit_zone))
- return hit_zone
- else //when a limb is missing the damage is actually passed to the chest
- return "chest"
-
-/obj/item/projectile/proc/prehit(atom/target)
- return
-
-/obj/item/projectile/proc/on_hit(atom/target, blocked = 0)
- var/turf/target_loca = get_turf(target)
- if(!isliving(target))
- if(impact_effect_type)
- new impact_effect_type(target_loca, target, src)
- return 0
- var/mob/living/L = target
- if(blocked != 100) // not completely blocked
- if(damage && L.blood_volume && damage_type == BRUTE)
- var/splatter_dir = dir
- if(starting)
- splatter_dir = get_dir(starting, target_loca)
- if(isalien(L))
- new /obj/effect/overlay/temp/dir_setting/bloodsplatter/xenosplatter(target_loca, splatter_dir)
- else
- new /obj/effect/overlay/temp/dir_setting/bloodsplatter(target_loca, splatter_dir)
- if(prob(33))
- L.add_splatter_floor(target_loca)
- else if(impact_effect_type)
- new impact_effect_type(target_loca, target, src)
-
- var/organ_hit_text = ""
- var/limb_hit = L.check_limb_hit(def_zone)//to get the correct message info.
- if(limb_hit)
- organ_hit_text = " in \the [parse_zone(limb_hit)]"
- if(suppressed)
- playsound(loc, hitsound, 5, 1, -1)
- to_chat(L, "You're shot by \a [src][organ_hit_text]!")
- else
- if(hitsound)
- var/volume = vol_by_damage()
- playsound(loc, hitsound, volume, 1, -1)
- L.visible_message("[L] is hit by \a [src][organ_hit_text]!", \
- "[L] is hit by \a [src][organ_hit_text]!", null, COMBAT_MESSAGE_RANGE)
- L.on_hit(src)
-
- var/reagent_note
- if(reagents && reagents.reagent_list)
- reagent_note = " REAGENTS:"
- for(var/datum/reagent/R in reagents.reagent_list)
- reagent_note += R.id + " ("
- reagent_note += num2text(R.volume) + ") "
-
- add_logs(firer, L, "shot", src, reagent_note)
- return L.apply_effects(stun, weaken, paralyze, irradiate, slur, stutter, eyeblur, drowsy, blocked, stamina, jitter)
-
-/obj/item/projectile/proc/vol_by_damage()
- if(src.damage)
- return Clamp((src.damage) * 0.67, 30, 100)// Multiply projectile damage by 0.67, then clamp the value between 30 and 100
- else
- return 50 //if the projectile doesn't do damage, play its hitsound at 50% volume
-
-/obj/item/projectile/Bump(atom/A, yes)
- if(!yes) //prevents double bumps.
- return
- if(firer)
- if(A == firer || (A == firer.loc && istype(A, /obj/mecha))) //cannot shoot yourself or your mech
- loc = A.loc
- return 0
-
- var/distance = get_dist(get_turf(A), starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations.
- def_zone = ran_zone(def_zone, max(100-(7*distance), 5)) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use.
-
- if(isturf(A) && hitsound_wall)
- var/volume = Clamp(vol_by_damage() + 20, 0, 100)
- if(suppressed)
- volume = 5
- playsound(loc, hitsound_wall, volume, 1, -1)
-
- var/turf/target_turf = get_turf(A)
-
- prehit(A)
- var/permutation = A.bullet_act(src, def_zone) // searches for return value, could be deleted after run so check A isn't null
- if(permutation == -1 || forcedodge)// the bullet passes through a dense object!
- loc = target_turf
- if(A)
- permutated.Add(A)
- return 0
- else
- if(A && A.density && !ismob(A) && !(A.flags & ON_BORDER)) //if we hit a dense non-border obj or dense turf then we also hit one of the mobs on that tile.
- var/list/mobs_list = list()
- for(var/mob/living/L in target_turf)
- mobs_list += L
- if(mobs_list.len)
- var/mob/living/picked_mob = pick(mobs_list)
- prehit(picked_mob)
- picked_mob.bullet_act(src, def_zone)
- qdel(src)
-
-/obj/item/projectile/Process_Spacemove(var/movement_dir = 0)
- return 1 //Bullets don't drift in space
-
-/obj/item/projectile/proc/fire(setAngle, atom/direct_target)
- if(!log_override && firer && original)
- add_logs(firer, original, "fired at", src, " [get_area(src)]")
- if(direct_target)
- prehit(direct_target)
- direct_target.bullet_act(src, def_zone)
- qdel(src)
- return
- if(setAngle)
- Angle = setAngle
- var/old_pixel_x = pixel_x
- var/old_pixel_y = pixel_y
- if(!legacy) //new projectiles
- set waitfor = 0
- var/next_run = world.time
- while(loc)
- if(paused)
- next_run = world.time
- sleep(1)
- continue
-
- if((!( current ) || loc == current))
- current = locate(Clamp(x+xo,1,world.maxx),Clamp(y+yo,1,world.maxy),z)
-
- if(!Angle)
- Angle=round(Get_Angle(src,current))
- if(spread)
- Angle += (rand() - 0.5) * spread
- var/matrix/M = new
- M.Turn(Angle)
- transform = M
-
- var/Pixel_x=round((sin(Angle)+16*sin(Angle)*2), 1) //round() is a floor operation when only one argument is supplied, we don't want that here
- var/Pixel_y=round((cos(Angle)+16*cos(Angle)*2), 1)
- var/pixel_x_offset = old_pixel_x + Pixel_x
- var/pixel_y_offset = old_pixel_y + Pixel_y
- var/new_x = x
- var/new_y = y
-
- while(pixel_x_offset > 16)
- pixel_x_offset -= 32
- old_pixel_x -= 32
- new_x++// x++
- while(pixel_x_offset < -16)
- pixel_x_offset += 32
- old_pixel_x += 32
- new_x--
- while(pixel_y_offset > 16)
- pixel_y_offset -= 32
- old_pixel_y -= 32
- new_y++
- while(pixel_y_offset < -16)
- pixel_y_offset += 32
- old_pixel_y += 32
- new_y--
-
- pixel_x = old_pixel_x
- pixel_y = old_pixel_y
- step_towards(src, locate(new_x, new_y, z))
- next_run += max(world.tick_lag, speed)
- var/delay = next_run - world.time
- if(delay <= world.tick_lag*2)
- pixel_x = pixel_x_offset
- pixel_y = pixel_y_offset
- else
- animate(src, pixel_x = pixel_x_offset, pixel_y = pixel_y_offset, time = max(1, (delay <= 3 ? delay - 1 : delay)), flags = ANIMATION_END_NOW)
- old_pixel_x = pixel_x_offset
- old_pixel_y = pixel_y_offset
-
- if(original && (original.layer>=2.75) || ismob(original))
- if(loc == get_turf(original))
- if(!(original in permutated))
- Bump(original, 1)
- Range()
- if (delay > 0)
- sleep(delay)
-
- else //old projectile system
- set waitfor = 0
- while(loc)
- if(!paused)
- if((!( current ) || loc == current))
- current = locate(Clamp(x+xo,1,world.maxx),Clamp(y+yo,1,world.maxy),z)
- step_towards(src, current)
- if(original && (original.layer>=2.75) || ismob(original))
- if(loc == get_turf(original))
- if(!(original in permutated))
- Bump(original, 1)
- Range()
- sleep(config.run_speed * 0.9)
-
-
-/obj/item/projectile/proc/preparePixelProjectile(atom/target, var/turf/targloc, mob/living/user, params, spread)
- var/turf/curloc = get_turf(user)
- src.loc = get_turf(user)
- src.starting = get_turf(user)
- src.current = curloc
- src.yo = targloc.y - curloc.y
- src.xo = targloc.x - curloc.x
-
- if(params)
- var/list/mouse_control = params2list(params)
- if(mouse_control["icon-x"])
- src.p_x = text2num(mouse_control["icon-x"])
- if(mouse_control["icon-y"])
- src.p_y = text2num(mouse_control["icon-y"])
- if(mouse_control["screen-loc"])
- //Split screen-loc up into X+Pixel_X and Y+Pixel_Y
- var/list/screen_loc_params = splittext(mouse_control["screen-loc"], ",")
-
- //Split X+Pixel_X up into list(X, Pixel_X)
- var/list/screen_loc_X = splittext(screen_loc_params[1],":")
-
- //Split Y+Pixel_Y up into list(Y, Pixel_Y)
- var/list/screen_loc_Y = splittext(screen_loc_params[2],":")
- // to_chat(world, "X: [screen_loc_X[1]] PixelX: [screen_loc_X[2]] / Y: [screen_loc_Y[1]] PixelY: [screen_loc_Y[2]]")
- var/x = text2num(screen_loc_X[1]) * 32 + text2num(screen_loc_X[2]) - 32
- var/y = text2num(screen_loc_Y[1]) * 32 + text2num(screen_loc_Y[2]) - 32
-
- //Calculate the "resolution" of screen based on client's view and world's icon size. This will work if the user can view more tiles than average.
- var/screenview = (user.client.view * 2 + 1) * world.icon_size //Refer to http://www.byond.com/docs/ref/info.html#/client/var/view for mad maths
-
- var/ox = round(screenview/2) //"origin" x
- var/oy = round(screenview/2) //"origin" y
- // to_chat(world, "Pixel position: [x] [y]")
- var/angle = Atan2(y - oy, x - ox)
- // to_chat(world, "Angle: [angle]")
- src.Angle = angle
- if(spread)
- src.Angle += spread
-
-
-/obj/item/projectile/Crossed(atom/movable/AM) //A mob moving on a tile with a projectile is hit by it.
- ..()
- if(isliving(AM) && AM.density && !checkpass(PASSMOB))
- Bump(AM, 1)
-
-/obj/item/projectile/Destroy()
- return ..()
-
-/obj/item/projectile/experience_pressure_difference()
- return
+/obj/item/projectile
+ name = "projectile"
+ icon = 'icons/obj/projectiles.dmi'
+ icon_state = "bullet"
+ density = 0
+ anchored = 1
+ flags = ABSTRACT
+ pass_flags = PASSTABLE
+ mouse_opacity = 0
+ hitsound = 'sound/weapons/pierce.ogg'
+ var/hitsound_wall = ""
+
+ resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
+ var/def_zone = "" //Aiming at
+ var/mob/firer = null//Who shot it
+ var/suppressed = 0 //Attack message
+ var/yo = null
+ var/xo = null
+ var/current = null
+ var/atom/original = null // the original target clicked
+ var/turf/starting = null // the projectile's starting turf
+ var/list/permutated = list() // we've passed through these atoms, don't try to hit them again
+ var/paused = FALSE //for suspending the projectile midair
+ var/p_x = 16
+ var/p_y = 16 // the pixel location of the tile that the player clicked. Default is the center
+ var/speed = 0.8 //Amount of deciseconds it takes for projectile to travel
+ var/Angle = 0
+ var/spread = 0 //amount (in degrees) of projectile spread
+ var/legacy = 0 //legacy projectile system
+ animate_movement = 0 //Use SLIDE_STEPS in conjunction with legacy
+
+ var/damage = 10
+ var/damage_type = BRUTE //BRUTE, BURN, TOX, OXY, CLONE are the only things that should be in here
+ var/nodamage = 0 //Determines if the projectile will skip any damage inflictions
+ var/flag = "bullet" //Defines what armor to use when it hits things. Must be set to bullet, laser, energy,or bomb
+ var/projectile_type = /obj/item/projectile
+ var/range = 50 //This will de-increment every step. When 0, it will delete the projectile.
+ //Effects
+ var/stun = 0
+ var/weaken = 0
+ var/paralyze = 0
+ var/irradiate = 0
+ var/stutter = 0
+ var/slur = 0
+ var/eyeblur = 0
+ var/drowsy = 0
+ var/stamina = 0
+ var/jitter = 0
+ var/forcedodge = 0 //to pass through everything
+ var/dismemberment = 0 //The higher the number, the greater the bonus to dismembering. 0 will not dismember at all.
+ var/impact_effect_type //what type of impact effect to show when hitting something
+ var/log_override = FALSE //is this type spammed enough to not log? (KAs)
+
+/obj/item/projectile/New()
+ permutated = list()
+ return ..()
+
+/obj/item/projectile/proc/Range()
+ range--
+ if(range <= 0 && loc)
+ on_range()
+
+/obj/item/projectile/proc/on_range() //if we want there to be effects when they reach the end of their range
+ qdel(src)
+
+//to get the correct limb (if any) for the projectile hit message
+/mob/living/proc/check_limb_hit(hit_zone)
+ if(has_limbs)
+ return hit_zone
+
+/mob/living/carbon/check_limb_hit(hit_zone)
+ if(get_bodypart(hit_zone))
+ return hit_zone
+ else //when a limb is missing the damage is actually passed to the chest
+ return "chest"
+
+/obj/item/projectile/proc/prehit(atom/target)
+ return
+
+/obj/item/projectile/proc/on_hit(atom/target, blocked = 0)
+ var/turf/target_loca = get_turf(target)
+ if(!isliving(target))
+ if(impact_effect_type)
+ new impact_effect_type(target_loca, target, src)
+ return 0
+ var/mob/living/L = target
+ if(blocked != 100) // not completely blocked
+ if(damage && L.blood_volume && damage_type == BRUTE)
+ var/splatter_dir = dir
+ if(starting)
+ splatter_dir = get_dir(starting, target_loca)
+ if(isalien(L))
+ new /obj/effect/overlay/temp/dir_setting/bloodsplatter/xenosplatter(target_loca, splatter_dir)
+ else
+ new /obj/effect/overlay/temp/dir_setting/bloodsplatter(target_loca, splatter_dir)
+ if(prob(33))
+ L.add_splatter_floor(target_loca)
+ else if(impact_effect_type)
+ new impact_effect_type(target_loca, target, src)
+
+ var/organ_hit_text = ""
+ var/limb_hit = L.check_limb_hit(def_zone)//to get the correct message info.
+ if(limb_hit)
+ organ_hit_text = " in \the [parse_zone(limb_hit)]"
+ if(suppressed)
+ playsound(loc, hitsound, 5, 1, -1)
+ to_chat(L, "You're shot by \a [src][organ_hit_text]!")
+ else
+ if(hitsound)
+ var/volume = vol_by_damage()
+ playsound(loc, hitsound, volume, 1, -1)
+ L.visible_message("[L] is hit by \a [src][organ_hit_text]!", \
+ "[L] is hit by \a [src][organ_hit_text]!", null, COMBAT_MESSAGE_RANGE)
+ L.on_hit(src)
+
+ var/reagent_note
+ if(reagents && reagents.reagent_list)
+ reagent_note = " REAGENTS:"
+ for(var/datum/reagent/R in reagents.reagent_list)
+ reagent_note += R.id + " ("
+ reagent_note += num2text(R.volume) + ") "
+
+ add_logs(firer, L, "shot", src, reagent_note)
+ return L.apply_effects(stun, weaken, paralyze, irradiate, slur, stutter, eyeblur, drowsy, blocked, stamina, jitter)
+
+/obj/item/projectile/proc/vol_by_damage()
+ if(src.damage)
+ return Clamp((src.damage) * 0.67, 30, 100)// Multiply projectile damage by 0.67, then clamp the value between 30 and 100
+ else
+ return 50 //if the projectile doesn't do damage, play its hitsound at 50% volume
+
+/obj/item/projectile/Bump(atom/A, yes)
+ if(!yes) //prevents double bumps.
+ return
+ if(firer)
+ if(A == firer || (A == firer.loc && istype(A, /obj/mecha))) //cannot shoot yourself or your mech
+ loc = A.loc
+ return 0
+
+ var/distance = get_dist(get_turf(A), starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations.
+ def_zone = ran_zone(def_zone, max(100-(7*distance), 5)) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use.
+
+ if(isturf(A) && hitsound_wall)
+ var/volume = Clamp(vol_by_damage() + 20, 0, 100)
+ if(suppressed)
+ volume = 5
+ playsound(loc, hitsound_wall, volume, 1, -1)
+
+ var/turf/target_turf = get_turf(A)
+
+ prehit(A)
+ var/permutation = A.bullet_act(src, def_zone) // searches for return value, could be deleted after run so check A isn't null
+ if(permutation == -1 || forcedodge)// the bullet passes through a dense object!
+ loc = target_turf
+ if(A)
+ permutated.Add(A)
+ return 0
+ else
+ if(A && A.density && !ismob(A) && !(A.flags & ON_BORDER)) //if we hit a dense non-border obj or dense turf then we also hit one of the mobs on that tile.
+ var/list/mobs_list = list()
+ for(var/mob/living/L in target_turf)
+ mobs_list += L
+ if(mobs_list.len)
+ var/mob/living/picked_mob = pick(mobs_list)
+ prehit(picked_mob)
+ picked_mob.bullet_act(src, def_zone)
+ qdel(src)
+
+/obj/item/projectile/Process_Spacemove(var/movement_dir = 0)
+ return 1 //Bullets don't drift in space
+
+/obj/item/projectile/proc/fire(setAngle, atom/direct_target)
+ if(!log_override && firer && original)
+ add_logs(firer, original, "fired at", src, " [get_area(src)]")
+ if(direct_target)
+ prehit(direct_target)
+ direct_target.bullet_act(src, def_zone)
+ qdel(src)
+ return
+ if(setAngle)
+ Angle = setAngle
+ var/old_pixel_x = pixel_x
+ var/old_pixel_y = pixel_y
+ if(!legacy) //new projectiles
+ set waitfor = 0
+ var/next_run = world.time
+ while(loc)
+ if(paused)
+ next_run = world.time
+ sleep(1)
+ continue
+
+ if((!( current ) || loc == current))
+ current = locate(Clamp(x+xo,1,world.maxx),Clamp(y+yo,1,world.maxy),z)
+
+ if(!Angle)
+ Angle=round(Get_Angle(src,current))
+ if(spread)
+ Angle += (rand() - 0.5) * spread
+ var/matrix/M = new
+ M.Turn(Angle)
+ transform = M
+
+ var/Pixel_x=round((sin(Angle)+16*sin(Angle)*2), 1) //round() is a floor operation when only one argument is supplied, we don't want that here
+ var/Pixel_y=round((cos(Angle)+16*cos(Angle)*2), 1)
+ var/pixel_x_offset = old_pixel_x + Pixel_x
+ var/pixel_y_offset = old_pixel_y + Pixel_y
+ var/new_x = x
+ var/new_y = y
+
+ while(pixel_x_offset > 16)
+ pixel_x_offset -= 32
+ old_pixel_x -= 32
+ new_x++// x++
+ while(pixel_x_offset < -16)
+ pixel_x_offset += 32
+ old_pixel_x += 32
+ new_x--
+ while(pixel_y_offset > 16)
+ pixel_y_offset -= 32
+ old_pixel_y -= 32
+ new_y++
+ while(pixel_y_offset < -16)
+ pixel_y_offset += 32
+ old_pixel_y += 32
+ new_y--
+
+ pixel_x = old_pixel_x
+ pixel_y = old_pixel_y
+ step_towards(src, locate(new_x, new_y, z))
+ next_run += max(world.tick_lag, speed)
+ var/delay = next_run - world.time
+ if(delay <= world.tick_lag*2)
+ pixel_x = pixel_x_offset
+ pixel_y = pixel_y_offset
+ else
+ animate(src, pixel_x = pixel_x_offset, pixel_y = pixel_y_offset, time = max(1, (delay <= 3 ? delay - 1 : delay)), flags = ANIMATION_END_NOW)
+ old_pixel_x = pixel_x_offset
+ old_pixel_y = pixel_y_offset
+
+ if(original && (original.layer>=2.75) || ismob(original))
+ if(loc == get_turf(original))
+ if(!(original in permutated))
+ Bump(original, 1)
+ Range()
+ if (delay > 0)
+ sleep(delay)
+
+ else //old projectile system
+ set waitfor = 0
+ while(loc)
+ if(!paused)
+ if((!( current ) || loc == current))
+ current = locate(Clamp(x+xo,1,world.maxx),Clamp(y+yo,1,world.maxy),z)
+ step_towards(src, current)
+ if(original && (original.layer>=2.75) || ismob(original))
+ if(loc == get_turf(original))
+ if(!(original in permutated))
+ Bump(original, 1)
+ Range()
+ sleep(config.run_speed * 0.9)
+
+
+/obj/item/projectile/proc/preparePixelProjectile(atom/target, var/turf/targloc, mob/living/user, params, spread)
+ var/turf/curloc = get_turf(user)
+ src.loc = get_turf(user)
+ src.starting = get_turf(user)
+ src.current = curloc
+ src.yo = targloc.y - curloc.y
+ src.xo = targloc.x - curloc.x
+
+ if(params)
+ var/list/mouse_control = params2list(params)
+ if(mouse_control["icon-x"])
+ src.p_x = text2num(mouse_control["icon-x"])
+ if(mouse_control["icon-y"])
+ src.p_y = text2num(mouse_control["icon-y"])
+ if(mouse_control["screen-loc"])
+ //Split screen-loc up into X+Pixel_X and Y+Pixel_Y
+ var/list/screen_loc_params = splittext(mouse_control["screen-loc"], ",")
+
+ //Split X+Pixel_X up into list(X, Pixel_X)
+ var/list/screen_loc_X = splittext(screen_loc_params[1],":")
+
+ //Split Y+Pixel_Y up into list(Y, Pixel_Y)
+ var/list/screen_loc_Y = splittext(screen_loc_params[2],":")
+ // to_chat(world, "X: [screen_loc_X[1]] PixelX: [screen_loc_X[2]] / Y: [screen_loc_Y[1]] PixelY: [screen_loc_Y[2]]")
+ var/x = text2num(screen_loc_X[1]) * 32 + text2num(screen_loc_X[2]) - 32
+ var/y = text2num(screen_loc_Y[1]) * 32 + text2num(screen_loc_Y[2]) - 32
+
+ //Calculate the "resolution" of screen based on client's view and world's icon size. This will work if the user can view more tiles than average.
+ var/screenview = (user.client.view * 2 + 1) * world.icon_size //Refer to http://www.byond.com/docs/ref/info.html#/client/var/view for mad maths
+
+ var/ox = round(screenview/2) //"origin" x
+ var/oy = round(screenview/2) //"origin" y
+ // to_chat(world, "Pixel position: [x] [y]")
+ var/angle = Atan2(y - oy, x - ox)
+ // to_chat(world, "Angle: [angle]")
+ src.Angle = angle
+ if(spread)
+ src.Angle += spread
+
+
+/obj/item/projectile/Crossed(atom/movable/AM) //A mob moving on a tile with a projectile is hit by it.
+ ..()
+ if(isliving(AM) && AM.density && !checkpass(PASSMOB))
+ Bump(AM, 1)
+
+/obj/item/projectile/Destroy()
+ return ..()
+
+/obj/item/projectile/experience_pressure_difference()
+ return