From 8bcaa54cbe92681b08f0d19353711b376368d391 Mon Sep 17 00:00:00 2001 From: CitadelStationBot Date: Thu, 18 May 2017 04:13:57 -0500 Subject: [PATCH] [MIRROR] Fixes language code ignoring holder restrictions (#858) * Fixes language code ignoring holder restrictions * resolve .rej file. --- code/__DEFINES/jobs.dm | 84 +- code/_onclick/hud/_defines.dm | 324 +-- code/_onclick/hud/hud.dm | 538 ++--- code/_onclick/hud/human.dm | 876 ++++---- code/datums/browser.dm | 2 +- code/game/atoms_movable.dm | 6 +- code/game/gamemodes/nuclear/pinpointer.dm | 354 ++-- .../machinery/computer/telecrystalconsoles.dm | 446 ++-- code/game/mecha/equipment/weapons/weapons.dm | 870 ++++---- code/game/objects/effects/landmarks.dm | 666 +++--- code/game/objects/effects/step_triggers.dm | 6 +- code/game/objects/items/devices/PDA/cart.dm | 1574 +++++++------- .../objects/items/robot/robot_upgrades.dm | 806 +++---- .../items/weapons/grenades/spawnergrenade.dm | 78 +- .../items/weapons/storage/uplink_kits.dm | 608 +++--- .../objects/items/weapons/vending_items.dm | 156 +- code/game/objects/structures/displaycase.dm | 722 +++---- code/modules/awaymissions/gateway.dm | 480 ++--- code/modules/clothing/head/collectable.dm | 294 +-- code/modules/detectivework/scanner.dm | 344 +-- code/modules/jobs/access.dm | 962 ++++----- code/modules/jobs/job_types/civilian.dm | 6 +- code/modules/jobs/jobs.dm | 216 +- code/modules/library/lib_readme.dm | 122 +- code/modules/mob/living/carbon/human/emote.dm | 356 ++-- .../mob/living/simple_animal/bot/bot.dm | 1844 ++++++++--------- .../mob/living/simple_animal/bot/secbot.dm | 842 ++++---- .../living/simple_animal/hostile/hivebot.dm | 112 +- code/modules/projectiles/ammunition/energy.dm | 472 ++--- code/modules/projectiles/projectile.dm | 626 +++--- 30 files changed, 7396 insertions(+), 7396 deletions(-) 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 +={" - - - - - -"} - for(var/datum/data/crime/c in active3.fields["mi_crim"]) - menu += "" - menu += "" - menu += "" - menu += "" - menu += "" - menu += "
CrimeDetailsAuthorTime Added
[c.crimeName][c.crimeDetails][c.author][c.time]
" - - menu += text("
\nMajor Crimes:") - - menu +={" - - - - - -"} - for(var/datum/data/crime/c in active3.fields["ma_crim"]) - menu += "" - menu += "" - menu += "" - menu += "" - menu += "" - menu += "
CrimeDetailsAuthorTime Added
[c.crimeName][c.crimeDetails][c.author][c.time]
" - - 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 += "
  1. #[SO.id] - [SO.pack.name] approved by [SO.orderer] [SO.reason ? "([SO.reason])":""]
  2. " - menu += "
" - - menu += "Current requests:
    " - for(var/S in SSshuttle.requestlist) - var/datum/supply_order/SO = S - menu += "
  1. #[SO.id] - [SO.pack.name] requested by [SO.orderer]
  2. " - 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 +={" + + + + + +"} + for(var/datum/data/crime/c in active3.fields["mi_crim"]) + menu += "" + menu += "" + menu += "" + menu += "" + menu += "" + menu += "
CrimeDetailsAuthorTime Added
[c.crimeName][c.crimeDetails][c.author][c.time]
" + + menu += text("
\nMajor Crimes:") + + menu +={" + + + + + +"} + for(var/datum/data/crime/c in active3.fields["ma_crim"]) + menu += "" + menu += "" + menu += "" + menu += "" + menu += "" + menu += "
CrimeDetailsAuthorTime Added
[c.crimeName][c.crimeDetails][c.author][c.time]
" + + 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 += "
  1. #[SO.id] - [SO.pack.name] approved by [SO.orderer] [SO.reason ? "([SO.reason])":""]
  2. " + menu += "
" + + menu += "Current requests:
    " + for(var/S in SSshuttle.requestlist) + var/datum/supply_order/SO = S + menu += "
  1. #[SO.id] - [SO.pack.name] requested by [SO.orderer]
  2. " + 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