mirror of
https://github.com/CHOMPstation/CHOMPstation.git
synced 2026-07-21 20:12:31 +01:00
Merge branch 'master' into robot
This commit is contained in:
@@ -180,7 +180,8 @@ Class Procs:
|
||||
air_master.mark_zone_update(B)
|
||||
|
||||
/connection_edge/zone/recheck()
|
||||
if(!A.air.compare(B.air))
|
||||
// Edges with only one side being vacuum need processing no matter how close.
|
||||
if(!A.air.compare(B.air, vacuum_exception = 1))
|
||||
air_master.mark_edge_active(src)
|
||||
|
||||
//Helper proc to get connections for a zone.
|
||||
@@ -235,7 +236,10 @@ Class Procs:
|
||||
air_master.mark_zone_update(A)
|
||||
|
||||
/connection_edge/unsimulated/recheck()
|
||||
if(!A.air.compare(air))
|
||||
// Edges with only one side being vacuum need processing no matter how close.
|
||||
// Note: This handles the glaring flaw of a room holding pressure while exposed to space, but
|
||||
// does not specially handle the less common case of a simulated room exposed to an unsimulated pressurized turf.
|
||||
if(!A.air.compare(air, vacuum_exception = 1))
|
||||
air_master.mark_edge_active(src)
|
||||
|
||||
proc/ShareHeat(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles)
|
||||
|
||||
+3
-13
@@ -95,14 +95,14 @@ obj/var/phoronproof = 0
|
||||
return
|
||||
|
||||
//Burn skin if exposed.
|
||||
if(vsc.plc.SKIN_BURNS)
|
||||
if(vsc.plc.SKIN_BURNS && (species.breath_type != "phoron"))
|
||||
if(!pl_head_protected() || !pl_suit_protected())
|
||||
burn_skin(0.75)
|
||||
if(prob(20)) src << "<span class='danger'>Your skin burns!</span>"
|
||||
updatehealth()
|
||||
|
||||
//Burn eyes if exposed.
|
||||
if(vsc.plc.EYE_BURNS)
|
||||
if(vsc.plc.EYE_BURNS && (species.breath_type != "phoron"))
|
||||
if(!head)
|
||||
if(!wear_mask)
|
||||
burn_eyes()
|
||||
@@ -118,22 +118,12 @@ obj/var/phoronproof = 0
|
||||
burn_eyes()
|
||||
|
||||
//Genetic Corruption
|
||||
if(vsc.plc.GENETIC_CORRUPTION)
|
||||
if(vsc.plc.GENETIC_CORRUPTION && (species.breath_type != "phoron"))
|
||||
if(rand(1,10000) < vsc.plc.GENETIC_CORRUPTION)
|
||||
randmutb(src)
|
||||
src << "<span class='danger'>High levels of toxins cause you to spontaneously mutate!</span>"
|
||||
domutcheck(src,null)
|
||||
|
||||
/mob/living/carbon/human/vox/pl_effects()
|
||||
//Handles all the bad things phoron can do to Vox.
|
||||
|
||||
//Contamination
|
||||
if(vsc.plc.CLOTH_CONTAMINATION) contaminate()
|
||||
|
||||
//Anything else requires them to not be dead.
|
||||
if(stat >= 2)
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/proc/burn_eyes()
|
||||
var/obj/item/organ/internal/eyes/E = internal_organs_by_name[O_EYES]
|
||||
if(E)
|
||||
|
||||
@@ -26,11 +26,13 @@
|
||||
#define BORGXRAY 0x4
|
||||
#define BORGMATERIAL 8
|
||||
|
||||
#define STANCE_IDLE 1
|
||||
#define STANCE_ALERT 2
|
||||
#define STANCE_ATTACK 3
|
||||
#define STANCE_ATTACKING 4
|
||||
#define STANCE_TIRED 5
|
||||
#define STANCE_IDLE 1 // Looking for targets if hostile. Does idle wandering.
|
||||
#define STANCE_ALERT 2 // Bears
|
||||
#define STANCE_ATTACK 3 // Attempting to get into attack position
|
||||
#define STANCE_ATTACKING 4 // Doing attacks
|
||||
#define STANCE_TIRED 5 // Bears
|
||||
#define STANCE_FOLLOW 6 // Following somone
|
||||
#define STANCE_BUSY 7 // Do nothing on life ticks (Other code is running)
|
||||
|
||||
#define LEFT 1
|
||||
#define RIGHT 2
|
||||
@@ -139,7 +141,7 @@
|
||||
#define INCAPACITATION_STUNNED 8
|
||||
#define INCAPACITATION_FORCELYING 16 //needs a better name - represents being knocked down BUT still conscious.
|
||||
#define INCAPACITATION_KNOCKOUT 32
|
||||
|
||||
#define INCAPACITATION_NONE 0
|
||||
|
||||
#define INCAPACITATION_DEFAULT (INCAPACITATION_RESTRAINED|INCAPACITATION_BUCKLED_FULLY)
|
||||
#define INCAPACITATION_KNOCKDOWN (INCAPACITATION_KNOCKOUT|INCAPACITATION_FORCELYING)
|
||||
|
||||
@@ -43,6 +43,18 @@
|
||||
if (isarea(A))
|
||||
return A
|
||||
|
||||
|
||||
/** Checks if any living humans are in a given area. */
|
||||
/proc/area_is_occupied(var/area/myarea)
|
||||
// Testing suggests looping over human_mob_list is quicker than looping over area contents
|
||||
for(var/mob/living/carbon/human/H in human_mob_list)
|
||||
if(H.stat >= DEAD) //Conditions for exclusion here, like if disconnected people start blocking it.
|
||||
continue
|
||||
var/area/A = get_area(H)
|
||||
if(A == myarea) //The loc of a turf is the area it is in.
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/proc/in_range(source, user)
|
||||
if(get_dist(source, user) <= 1)
|
||||
return 1
|
||||
|
||||
@@ -793,6 +793,26 @@ proc // Creates a single icon from a given /atom or /image. Only the first argu
|
||||
alpha_mask.Blend(image_overlay,ICON_OR)//OR so they are lumped together in a nice overlay.
|
||||
return alpha_mask//And now return the mask.
|
||||
|
||||
//getFlatIcon but generates an icon that can face ALL four directions. The only four.
|
||||
/proc/getCompoundIcon(atom/A)
|
||||
var/icon/north = getFlatIcon(A,defdir=NORTH,always_use_defdir=1)
|
||||
var/icon/south = getFlatIcon(A,defdir=SOUTH,always_use_defdir=1)
|
||||
var/icon/east = getFlatIcon(A,defdir=EAST,always_use_defdir=1)
|
||||
var/icon/west = getFlatIcon(A,defdir=WEST,always_use_defdir=1)
|
||||
|
||||
//Starts with a blank icon because of byond bugs.
|
||||
var/icon/full = icon('icons/effects/effects.dmi', "icon_state"="nothing")
|
||||
|
||||
full.Insert(north,dir=NORTH)
|
||||
full.Insert(south,dir=SOUTH)
|
||||
full.Insert(east,dir=EAST)
|
||||
full.Insert(west,dir=WEST)
|
||||
qdel(north)
|
||||
qdel(south)
|
||||
qdel(east)
|
||||
qdel(west)
|
||||
return full
|
||||
|
||||
/mob/proc/AddCamoOverlay(atom/A)//A is the atom which we are using as the overlay.
|
||||
var/icon/opacity_icon = new(A.icon, A.icon_state)//Don't really care for overlays/underlays.
|
||||
//Now we need to culculate overlays+underlays and add them together to form an image for a mask.
|
||||
|
||||
@@ -158,7 +158,8 @@
|
||||
using.alpha = ui_alpha
|
||||
src.adding += using
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box = new /obj/screen/inventory/hand()
|
||||
inv_box.hud = src
|
||||
inv_box.name = "r_hand"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "r_hand_inactive"
|
||||
@@ -173,7 +174,8 @@
|
||||
src.r_hand_hud_object = inv_box
|
||||
src.adding += inv_box
|
||||
|
||||
inv_box = new /obj/screen/inventory()
|
||||
inv_box = new /obj/screen/inventory/hand()
|
||||
inv_box.hud = src
|
||||
inv_box.name = "l_hand"
|
||||
inv_box.icon = ui_style
|
||||
inv_box.icon_state = "l_hand_inactive"
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
layer = 20.0
|
||||
unacidable = 1
|
||||
var/obj/master = null //A reference to the object in the slot. Grabs or items, generally.
|
||||
var/datum/hud/hud = null // A reference to the owner HUD, if any.
|
||||
|
||||
/obj/screen/Destroy()
|
||||
master = null
|
||||
@@ -507,3 +508,20 @@
|
||||
usr.update_inv_l_hand(0)
|
||||
usr.update_inv_r_hand(0)
|
||||
return 1
|
||||
|
||||
// Hand slots are special to handle the handcuffs overlay
|
||||
/obj/screen/inventory/hand
|
||||
var/image/handcuff_overlay
|
||||
|
||||
/obj/screen/inventory/hand/update_icon()
|
||||
..()
|
||||
if(!hud)
|
||||
return
|
||||
if(!handcuff_overlay)
|
||||
var/state = (hud.l_hand_hud_object == src) ? "l_hand_hud_handcuffs" : "r_hand_hud_handcuffs"
|
||||
handcuff_overlay = image("icon"='icons/mob/screen_gen.dmi', "icon_state"=state)
|
||||
overlays.Cut()
|
||||
if(hud.mymob && iscarbon(hud.mymob))
|
||||
var/mob/living/carbon/C = hud.mymob
|
||||
if(C.handcuffed)
|
||||
overlays |= handcuff_overlay
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
/datum/controller/process/mob/doWork()
|
||||
for(last_object in mob_list)
|
||||
var/mob/M = last_object
|
||||
if(isnull(M.gcDestroyed))
|
||||
if(M && isnull(M.gcDestroyed))
|
||||
try
|
||||
M.Life()
|
||||
catch(var/exception/e)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
/datum/controller/process/obj/doWork()
|
||||
for(last_object in processing_objects)
|
||||
var/datum/O = last_object
|
||||
if(isnull(O.gcDestroyed))
|
||||
if(O && isnull(O.gcDestroyed))
|
||||
try
|
||||
O:process()
|
||||
catch(var/exception/e)
|
||||
|
||||
@@ -84,6 +84,8 @@ var/global/datum/emergency_shuttle_controller/emergency_shuttle
|
||||
if(istype(A, /area/hallway))
|
||||
A.readyalert()
|
||||
|
||||
atc.reroute_traffic(yes = 1)
|
||||
|
||||
//calls the shuttle for a routine crew transfer
|
||||
/datum/emergency_shuttle_controller/proc/call_transfer()
|
||||
if(!can_call()) return
|
||||
@@ -98,6 +100,7 @@ var/global/datum/emergency_shuttle_controller/emergency_shuttle
|
||||
shuttle.move_time = SHUTTLE_TRANSIT_DURATION
|
||||
|
||||
priority_announcement.Announce(replacetext(replacetext(using_map.shuttle_called_message, "%dock_name%", "[using_map.dock_name]"), "%ETA%", "[estimated_time] minute\s"))
|
||||
atc.shift_ending()
|
||||
|
||||
//recalls the shuttle
|
||||
/datum/emergency_shuttle_controller/proc/recall()
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
name = "Inflatable barriers"
|
||||
contains = list(/obj/item/weapon/storage/briefcase/inflatable = 3)
|
||||
cost = 20
|
||||
containertype = /obj/structure/closet/crate
|
||||
containertype = /obj/structure/closet/crate/engineering
|
||||
containername = "Inflatable Barrier Crate"
|
||||
|
||||
/datum/supply_packs/atmos/canister_empty
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
name = "Superconducting Magnetic Coil"
|
||||
contains = list(/obj/item/weapon/smes_coil)
|
||||
cost = 75
|
||||
containertype = /obj/structure/closet/crate
|
||||
containertype = /obj/structure/closet/crate/engineering
|
||||
containername = "Superconducting Magnetic Coil crate"
|
||||
|
||||
/datum/supply_packs/eng/electrical
|
||||
@@ -30,7 +30,7 @@
|
||||
/obj/item/weapon/cell/high = 2
|
||||
)
|
||||
cost = 10
|
||||
containertype = /obj/structure/closet/crate
|
||||
containertype = /obj/structure/closet/crate/engineering/electrical
|
||||
containername = "Electrical maintenance crate"
|
||||
|
||||
/datum/supply_packs/eng/mechanical
|
||||
@@ -42,7 +42,7 @@
|
||||
/obj/item/clothing/head/hardhat
|
||||
)
|
||||
cost = 10
|
||||
containertype = /obj/structure/closet/crate
|
||||
containertype = /obj/structure/closet/crate/engineering
|
||||
containername = "Mechanical maintenance crate"
|
||||
|
||||
/datum/supply_packs/eng/fueltank
|
||||
@@ -61,34 +61,35 @@
|
||||
/obj/item/weapon/paper/solar
|
||||
)
|
||||
cost = 20
|
||||
containertype = /obj/structure/closet/crate
|
||||
containertype = /obj/structure/closet/crate/engineering
|
||||
containername = "Solar pack crate"
|
||||
|
||||
/datum/supply_packs/eng/engine
|
||||
name = "Emitter crate"
|
||||
contains = list(/obj/machinery/power/emitter = 2)
|
||||
cost = 10
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
containertype = /obj/structure/closet/crate/secure/engineering
|
||||
containername = "Emitter crate"
|
||||
access = access_ce
|
||||
|
||||
/datum/supply_packs/eng/engine/field_gen
|
||||
name = "Field Generator crate"
|
||||
contains = list(/obj/machinery/field_generator = 2)
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
containertype = /obj/structure/closet/crate/secure/engineering
|
||||
containername = "Field Generator crate"
|
||||
access = access_ce
|
||||
|
||||
/datum/supply_packs/eng/engine/sing_gen
|
||||
name = "Singularity Generator crate"
|
||||
contains = list(/obj/machinery/the_singularitygen)
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
containertype = /obj/structure/closet/crate/secure/engineering
|
||||
containername = "Singularity Generator crate"
|
||||
access = access_ce
|
||||
|
||||
/datum/supply_packs/eng/engine/collector
|
||||
name = "Collector crate"
|
||||
contains = list(/obj/machinery/power/rad_collector = 3)
|
||||
containertype = /obj/structure/closet/crate/secure/engineering
|
||||
containername = "Collector crate"
|
||||
|
||||
/datum/supply_packs/eng/engine/PA
|
||||
@@ -103,7 +104,7 @@
|
||||
/obj/structure/particle_accelerator/power_box,
|
||||
/obj/structure/particle_accelerator/end_cap
|
||||
)
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
containertype = /obj/structure/closet/crate/secure/engineering
|
||||
containername = "Particle Accelerator crate"
|
||||
access = access_ce
|
||||
|
||||
@@ -111,7 +112,7 @@
|
||||
contains = list(/obj/item/weapon/circuitboard/shield_gen)
|
||||
name = "Bubble shield generator circuitry"
|
||||
cost = 30
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
containertype = /obj/structure/closet/crate/secure/engineering
|
||||
containername = "bubble shield generator circuitry crate"
|
||||
access = access_ce
|
||||
|
||||
@@ -119,7 +120,7 @@
|
||||
contains = list(/obj/item/weapon/circuitboard/shield_gen_ex)
|
||||
name = "Hull shield generator circuitry"
|
||||
cost = 30
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
containertype = /obj/structure/closet/crate/secure/engineering
|
||||
containername = "hull shield generator circuitry crate"
|
||||
access = access_ce
|
||||
|
||||
@@ -127,7 +128,7 @@
|
||||
contains = list(/obj/item/weapon/circuitboard/shield_cap)
|
||||
name = "Bubble shield capacitor circuitry"
|
||||
cost = 30
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
containertype = /obj/structure/closet/crate/secure/engineering
|
||||
containername = "shield capacitor circuitry crate"
|
||||
access = access_ce
|
||||
|
||||
@@ -169,7 +170,7 @@
|
||||
name = "P.A.C.M.A.N. portable generator parts"
|
||||
cost = 25
|
||||
containername = "P.A.C.M.A.N. Portable Generator Construction Kit"
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
containertype = /obj/structure/closet/crate/secure/engineering
|
||||
access = access_tech_storage
|
||||
contains = list(
|
||||
/obj/item/weapon/stock_parts/micro_laser,
|
||||
@@ -182,7 +183,7 @@
|
||||
name = "Super P.A.C.M.A.N. portable generator parts"
|
||||
cost = 35
|
||||
containername = "Super P.A.C.M.A.N. portable generator construction kit"
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
containertype = /obj/structure/closet/crate/secure/engineering
|
||||
access = access_tech_storage
|
||||
contains = list(
|
||||
/obj/item/weapon/stock_parts/micro_laser,
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
/obj/item/weapon/cell/high = 2
|
||||
)
|
||||
cost = 10
|
||||
containertype = /obj/structure/closet/crate/secure/gear
|
||||
containertype = /obj/structure/closet/crate/secure/science
|
||||
containername = "Robotics assembly"
|
||||
access = access_robotics
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
name = "All robolimb blueprints"
|
||||
contains = list(
|
||||
/obj/item/weapon/disk/limb/bishop,
|
||||
/obj/item/weapon/disk/limb/hesphiastos,
|
||||
/obj/item/weapon/disk/limb/hephaestus,
|
||||
/obj/item/weapon/disk/limb/morpheus,
|
||||
/obj/item/weapon/disk/limb/veymed,
|
||||
/obj/item/weapon/disk/limb/wardtakahashi,
|
||||
@@ -56,7 +56,7 @@
|
||||
name = "Morpheus robolimb blueprints"
|
||||
contains = list(/obj/item/weapon/disk/limb/morpheus)
|
||||
cost = 20
|
||||
containertype = /obj/structure/closet/crate/secure/gear
|
||||
containertype = /obj/structure/closet/crate/secure/science
|
||||
containername = "Robolimb blueprints (Morpheus)"
|
||||
access = access_robotics
|
||||
|
||||
@@ -64,15 +64,22 @@
|
||||
name = "Xion robolimb blueprints"
|
||||
contains = list(/obj/item/weapon/disk/limb/xion)
|
||||
cost = 20
|
||||
containertype = /obj/structure/closet/crate/secure/gear
|
||||
containertype = /obj/structure/closet/crate/secure/science
|
||||
containername = "Robolimb blueprints (Xion)"
|
||||
access = access_robotics
|
||||
|
||||
/datum/supply_packs/robotics/robolimbs/hephaestus
|
||||
name = "Hephaistos robolimb blueprints"
|
||||
contains = list(/obj/item/weapon/disk/limb/hephaestus)
|
||||
containertype = /obj/structure/closet/crate/secure/gear
|
||||
containername = "Robolimb blueprints (Hephaestus)"
|
||||
access = access_robotics
|
||||
|
||||
/datum/supply_packs/robotics/robolimbs/wardtakahashi
|
||||
name = "Ward-Takahashi robolimb blueprints"
|
||||
contains = list(/obj/item/weapon/disk/limb/wardtakahashi)
|
||||
cost = 35
|
||||
containertype = /obj/structure/closet/crate/secure/gear
|
||||
containertype = /obj/structure/closet/crate/secure/science
|
||||
containername = "Robolimb blueprints (Ward-Takahashi)"
|
||||
access = access_robotics
|
||||
|
||||
@@ -80,7 +87,7 @@
|
||||
name = "Zeng Hu robolimb blueprints"
|
||||
contains = list(/obj/item/weapon/disk/limb/zenghu)
|
||||
cost = 35
|
||||
containertype = /obj/structure/closet/crate/secure/gear
|
||||
containertype = /obj/structure/closet/crate/secure/science
|
||||
containername = "Robolimb blueprints (Zeng Hu)"
|
||||
access = access_robotics
|
||||
|
||||
@@ -88,7 +95,7 @@
|
||||
name = "Bishop robolimb blueprints"
|
||||
contains = list(/obj/item/weapon/disk/limb/bishop)
|
||||
cost = 70
|
||||
containertype = /obj/structure/closet/crate/secure/gear
|
||||
containertype = /obj/structure/closet/crate/secure/science
|
||||
containername = "Robolimb blueprints (Bishop)"
|
||||
access = access_robotics
|
||||
|
||||
@@ -96,7 +103,7 @@
|
||||
name = "Vey-Med robolimb blueprints"
|
||||
contains = list(/obj/item/weapon/disk/limb/veymed)
|
||||
cost = 70
|
||||
containertype = /obj/structure/closet/crate/secure/gear
|
||||
containertype = /obj/structure/closet/crate/secure/science
|
||||
containername = "Robolimb blueprints (Vey-Med)"
|
||||
access = access_robotics
|
||||
|
||||
@@ -108,7 +115,7 @@
|
||||
/obj/item/weapon/circuitboard/mecha/ripley/peripherals
|
||||
)
|
||||
cost = 25
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
containertype = /obj/structure/closet/crate/secure/science
|
||||
containername = "APLU \"Ripley\" Circuit Crate"
|
||||
access = access_robotics
|
||||
|
||||
@@ -119,7 +126,7 @@
|
||||
/obj/item/weapon/circuitboard/mecha/odysseus/main
|
||||
)
|
||||
cost = 25
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
containertype = /obj/structure/closet/crate/secure/science
|
||||
containername = "\"Odysseus\" Circuit Crate"
|
||||
access = access_robotics
|
||||
|
||||
@@ -133,7 +140,7 @@
|
||||
)
|
||||
name = "Random APLU modkit"
|
||||
cost = 200
|
||||
containertype = /obj/structure/closet/crate
|
||||
containertype = /obj/structure/closet/crate/science
|
||||
containername = "heavy crate"
|
||||
|
||||
/datum/supply_packs/randomised/robotics/exosuit_mod/durand
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/datum/wires/jukebox
|
||||
random = 1
|
||||
holder_type = /obj/machinery/media/jukebox
|
||||
wire_count = 7
|
||||
wire_count = 11
|
||||
|
||||
var/const/WIRE_POWER = 1
|
||||
var/const/WIRE_HACK = 2
|
||||
@@ -10,6 +10,10 @@ var/const/WIRE_SPEEDDOWN = 8
|
||||
var/const/WIRE_REVERSE = 16
|
||||
var/const/WIRE_NOTHING1 = 32
|
||||
var/const/WIRE_NOTHING2 = 64
|
||||
var/const/WIRE_START = 128
|
||||
var/const/WIRE_STOP = 256
|
||||
var/const/WIRE_PREV = 512
|
||||
var/const/WIRE_NEXT = 1024
|
||||
|
||||
/datum/wires/jukebox/CanUse(var/mob/living/L)
|
||||
var/obj/machinery/media/jukebox/A = holder
|
||||
@@ -40,6 +44,14 @@ var/const/WIRE_NOTHING2 = 64
|
||||
holder.visible_message("<span class='notice'>\icon[holder] The speakers squeaks.</span>")
|
||||
if(WIRE_SPEEDDOWN)
|
||||
holder.visible_message("<span class='notice'>\icon[holder] The speakers rumble.</span>")
|
||||
if(WIRE_START)
|
||||
A.StartPlaying()
|
||||
if(WIRE_STOP)
|
||||
A.StopPlaying()
|
||||
if(WIRE_PREV)
|
||||
A.PrevTrack()
|
||||
if(WIRE_NEXT)
|
||||
A.NextTrack()
|
||||
else
|
||||
A.shock(usr, 10) // The nothing wires give a chance to shock just for fun
|
||||
|
||||
|
||||
@@ -125,8 +125,17 @@
|
||||
if(A:lying) continue
|
||||
src.throw_impact(A,speed)
|
||||
if(isobj(A))
|
||||
if(A.density && !A.throwpass) // **TODO: Better behaviour for windows which are dense, but shouldn't always stop movement
|
||||
src.throw_impact(A,speed)
|
||||
if(!A.density || A.throwpass)
|
||||
continue
|
||||
// Special handling of windows, which are dense but block only from some directions
|
||||
if(istype(A, /obj/structure/window))
|
||||
var/obj/structure/window/W = A
|
||||
if (!W.is_full_window() && !(turn(src.last_move, 180) & A.dir))
|
||||
continue
|
||||
// Same thing for (closed) windoors, which have the same problem
|
||||
else if(istype(A, /obj/machinery/door/window) && !(turn(src.last_move, 180) & A.dir))
|
||||
continue
|
||||
src.throw_impact(A,speed)
|
||||
|
||||
/atom/movable/proc/throw_at(atom/target, range, speed, thrower)
|
||||
if(!target || !src) return 0
|
||||
|
||||
@@ -95,11 +95,15 @@
|
||||
|
||||
changeling.chem_charges -= 20
|
||||
|
||||
var/range_heavy = 2
|
||||
var/range_light = 5
|
||||
var/range_heavy = 1
|
||||
var/range_med = 2
|
||||
var/range_light = 4
|
||||
var/range_long = 6
|
||||
if(src.mind.changeling.recursive_enhancement)
|
||||
range_heavy = range_heavy * 2
|
||||
range_med = range_med * 2
|
||||
range_light = range_light * 2
|
||||
range_long = range_long * 2
|
||||
src << "<span class='notice'>We are extra loud.</span>"
|
||||
src.mind.changeling.recursive_enhancement = 0
|
||||
|
||||
|
||||
@@ -231,7 +231,7 @@ var/list/sacrificed = list()
|
||||
if(T)
|
||||
T.hotspot_expose(700,125)
|
||||
var/rune = src // detaching the proc - in theory
|
||||
empulse(U, (range_red - 2), range_red)
|
||||
empulse(U, (range_red - 3), (range_red - 2), (range_red - 1), range_red)
|
||||
qdel(rune)
|
||||
return
|
||||
|
||||
|
||||
@@ -350,6 +350,11 @@ Would like to add a law like "Law x is _______" where x = a number, and _____ is
|
||||
M << "<br>"
|
||||
M.add_ion_law("THE STATION IS [who2pref] [who2]")
|
||||
|
||||
if(botEmagChance)
|
||||
for(var/mob/living/bot/bot in machines)
|
||||
if(prob(botEmagChance))
|
||||
bot.emag_act(1)
|
||||
|
||||
/*
|
||||
|
||||
var/apcnum = 0
|
||||
|
||||
@@ -254,7 +254,7 @@
|
||||
..()
|
||||
// Best case scenario: Comparable to a low-yield EMP grenade.
|
||||
// Worst case scenario: Comparable to a standard yield EMP grenade.
|
||||
empulse(src, rand(2, 4), rand(4, 10))
|
||||
empulse(src, rand(1, 3), rand(2, 4), rand(3, 7), rand(5, 10))
|
||||
|
||||
//Station buster Tunguska
|
||||
/obj/effect/meteor/tunguska
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
safe_blink(src, range = 6)
|
||||
src << "<span class='warning'>You're teleported against your will!</span>"
|
||||
if(4)
|
||||
emp_act(2)
|
||||
emp_act(3)
|
||||
|
||||
if(51 to 100) //Severe
|
||||
rng = rand(0,3)
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
/mob/living/simple_animal/hostile/carp,
|
||||
/mob/living/simple_animal/hostile/scarybat,
|
||||
/mob/living/simple_animal/hostile/viscerator,
|
||||
/mob/living/simple_animal/hostile/retaliate/malf_drone,
|
||||
/mob/living/simple_animal/hostile/malf_drone,
|
||||
/mob/living/simple_animal/hostile/giant_spider,
|
||||
/mob/living/simple_animal/hostile/hivebot,
|
||||
/mob/living/simple_animal/hostile/diyaab, //Doubt these will get used but might as well,
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
..()
|
||||
|
||||
/obj/item/weapon/spell/spawner/pulsar/on_throw_cast(atom/hit_atom, mob/user)
|
||||
empulse(hit_atom, 1, 1, log=1)
|
||||
empulse(hit_atom, 1, 1, 1, 1, log=1)
|
||||
|
||||
/obj/effect/temporary_effect/pulsar
|
||||
name = "pulsar"
|
||||
@@ -44,7 +44,7 @@
|
||||
/obj/effect/temporary_effect/pulsar/proc/pulse_loop()
|
||||
while(pulses_remaining)
|
||||
sleep(2 SECONDS)
|
||||
empulse(src, heavy_range = 1, light_range = 2, log = 1)
|
||||
empulse(src, 1, 1, 2, 2, log = 1)
|
||||
pulses_remaining--
|
||||
qdel(src)
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"Chick" = /mob/living/simple_animal/chick,
|
||||
"Crab" = /mob/living/simple_animal/crab,
|
||||
"Parrot" = /mob/living/simple_animal/parrot,
|
||||
"Goat" = /mob/living/simple_animal/hostile/retaliate/goat,
|
||||
"Goat" = /mob/living/simple_animal/retaliate/goat,
|
||||
"Cat" = /mob/living/simple_animal/cat,
|
||||
"Kitten" = /mob/living/simple_animal/cat/kitten,
|
||||
"Corgi" = /mob/living/simple_animal/corgi,
|
||||
|
||||
@@ -335,17 +335,16 @@
|
||||
organStatus["bleeding"] = 1
|
||||
if(E.status & ORGAN_DEAD)
|
||||
organStatus["dead"] = 1
|
||||
for(var/datum/wound/W in E.wounds)
|
||||
if(W.internal)
|
||||
organStatus["internalBleeding"] = 1
|
||||
break
|
||||
|
||||
organData["status"] = organStatus
|
||||
|
||||
if(istype(E, /obj/item/organ/external/chest) && H.is_lung_ruptured())
|
||||
organData["lungRuptured"] = 1
|
||||
|
||||
for(var/datum/wound/W in E.wounds)
|
||||
if(W.internal)
|
||||
organData["internalBleeding"] = 1
|
||||
break
|
||||
|
||||
extOrganData.Add(list(organData))
|
||||
|
||||
occupantData["extOrgan"] = extOrganData
|
||||
|
||||
@@ -348,7 +348,7 @@ update_flag
|
||||
"\[N2O\]" = "redws", \
|
||||
"\[N2\]" = "red", \
|
||||
"\[O2\]" = "blue", \
|
||||
"\[Phoron\]" = "purple", \
|
||||
"\[Phoron\]" = "orangeps", \
|
||||
"\[CO2\]" = "black", \
|
||||
"\[Air\]" = "grey", \
|
||||
"\[CAUTION\]" = "yellow", \
|
||||
|
||||
@@ -66,7 +66,11 @@
|
||||
if(1)
|
||||
num_of_prizes = rand(1,4)
|
||||
if(2)
|
||||
num_of_prizes = rand(1,3)
|
||||
if(3)
|
||||
num_of_prizes = rand(0,2)
|
||||
if(4)
|
||||
num_of_prizes = rand(0,1)
|
||||
for(num_of_prizes; num_of_prizes > 0; num_of_prizes--)
|
||||
empprize = pickweight(prizes)
|
||||
new empprize(src.loc)
|
||||
|
||||
@@ -35,10 +35,12 @@
|
||||
var/stat_msg1
|
||||
var/stat_msg2
|
||||
|
||||
var/datum/lore/atc_controller/ATC
|
||||
var/datum/announcement/priority/crew_announcement = new
|
||||
|
||||
/obj/machinery/computer/communications/New()
|
||||
..()
|
||||
ATC = atc
|
||||
crew_announcement.newscast = 1
|
||||
|
||||
/obj/machinery/computer/communications/process()
|
||||
@@ -130,6 +132,8 @@
|
||||
if("messagelist")
|
||||
src.currmsg = 0
|
||||
src.state = STATE_MESSAGELIST
|
||||
if("toggleatc")
|
||||
src.ATC.squelched = !src.ATC.squelched
|
||||
if("viewmessage")
|
||||
src.state = STATE_VIEWMESSAGE
|
||||
if (!src.currmsg)
|
||||
@@ -311,6 +315,7 @@
|
||||
else
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=login'>Log In</A> \]"
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=messagelist'>Message List</A> \]"
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=toggleatc'>[ATC.squelched ? "Enable" : "Disable"] ATC Relay</A> \]"
|
||||
if(STATE_CALLSHUTTLE)
|
||||
dat += "Are you sure you want to call the shuttle? \[ <A HREF='?src=\ref[src];operation=callshuttle2'>OK</A> | <A HREF='?src=\ref[src];operation=main'>Cancel</A> \]"
|
||||
if(STATE_CANCELSHUTTLE)
|
||||
@@ -374,6 +379,7 @@
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=ai-callshuttle'>Call Emergency Shuttle</A> \]"
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=ai-messagelist'>Message List</A> \]"
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=ai-status'>Set Status Display</A> \]"
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=toggleatc'>[ATC.squelched ? "Enable" : "Disable"] ATC Relay</A> \]"
|
||||
if(STATE_CALLSHUTTLE)
|
||||
dat += "Are you sure you want to call the shuttle? \[ <A HREF='?src=\ref[src];operation=ai-callshuttle2'>OK</A> | <A HREF='?src=\ref[src];operation=ai-main'>Cancel</A> \]"
|
||||
if(STATE_MESSAGELIST)
|
||||
|
||||
@@ -37,7 +37,16 @@
|
||||
/obj/machinery/door/airlock/attack_generic(var/mob/user, var/damage)
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
if(damage >= 10)
|
||||
if(src.density)
|
||||
if(src.locked || src.welded)
|
||||
visible_message("<span class='danger'>\The [user] begins breaking into \the [src] internals!</span>")
|
||||
if(do_after(user,10 SECONDS,src))
|
||||
src.locked = 0
|
||||
src.welded = 0
|
||||
update_icon()
|
||||
open(1)
|
||||
if(prob(25))
|
||||
src.shock(user, 100)
|
||||
else if(src.density)
|
||||
visible_message("<span class='danger'>\The [user] forces \the [src] open!</span>")
|
||||
open(1)
|
||||
else
|
||||
@@ -329,6 +338,18 @@
|
||||
secured_wires = 1
|
||||
assembly_type = /obj/structure/door_assembly/door_assembly_highsecurity
|
||||
|
||||
/obj/machinery/door/airlock/voidcraft
|
||||
name = "voidcraft hatch"
|
||||
desc = "It's an extra resilient airlock intended for spacefaring vessels."
|
||||
icon = 'icons/obj/doors/shuttledoors.dmi'
|
||||
explosion_resistance = 20
|
||||
assembly_type = /obj/structure/door_assembly/door_assembly_voidcraft
|
||||
|
||||
// Airlock opens from top-bottom instead of left-right.
|
||||
/obj/machinery/door/airlock/voidcraft/vertical
|
||||
icon = 'icons/obj/doors/shuttledoors_vertical.dmi'
|
||||
assembly_type = /obj/structure/door_assembly/door_assembly_voidcraft/vertical
|
||||
|
||||
/*
|
||||
About the new airlock wires panel:
|
||||
* An airlock wire dialog can be accessed by the normal way or by using wirecutters or a multitool on the door while the wire-panel is open. This would show the following wires, which you can either wirecut/mend or send a multitool pulse through. There are 9 wires.
|
||||
|
||||
@@ -269,4 +269,24 @@ datum/track/New(var/title_name, var/audio)
|
||||
|
||||
playing = 1
|
||||
update_use_power(2)
|
||||
update_icon()
|
||||
update_icon()
|
||||
|
||||
// Advance to the next track - Don't start playing it unless we were already playing
|
||||
/obj/machinery/media/jukebox/proc/NextTrack()
|
||||
if(!tracks.len) return
|
||||
var/curTrackIndex = max(1, tracks.Find(current_track))
|
||||
var/newTrackIndex = (curTrackIndex % tracks.len) + 1 // Loop back around if past end
|
||||
current_track = tracks[newTrackIndex]
|
||||
if(playing)
|
||||
StartPlaying()
|
||||
updateDialog()
|
||||
|
||||
// Advance to the next track - Don't start playing it unless we were already playing
|
||||
/obj/machinery/media/jukebox/proc/PrevTrack()
|
||||
if(!tracks.len) return
|
||||
var/curTrackIndex = max(1, tracks.Find(current_track))
|
||||
var/newTrackIndex = curTrackIndex == 1 ? tracks.len : curTrackIndex - 1
|
||||
current_track = tracks[newTrackIndex]
|
||||
if(playing)
|
||||
StartPlaying()
|
||||
updateDialog()
|
||||
|
||||
@@ -1,52 +1,45 @@
|
||||
// Navigation beacon for AI robots
|
||||
// Functions as a transponder: looks for incoming signal matching
|
||||
|
||||
var/global/list/navbeacons // no I don't like putting this in, but it will do for now
|
||||
var/global/list/navbeacons = list() // no I don't like putting this in, but it will do for now
|
||||
|
||||
/obj/machinery/navbeacon
|
||||
icon = 'icons/obj/objects.dmi'
|
||||
icon_state = "navbeacon0-f"
|
||||
name = "navigation beacon"
|
||||
desc = "A radio beacon used for bot navigation."
|
||||
desc = "A beacon used for bot navigation."
|
||||
level = 1 // underfloor
|
||||
layer = 2.5
|
||||
anchored = 1
|
||||
var/open = 0 // true if cover is open
|
||||
var/locked = 1 // true if controls are locked
|
||||
var/freq = 1445 // radio frequency
|
||||
var/freq = null // DEPRECATED we don't use radios anymore!
|
||||
var/location = "" // location response text
|
||||
var/list/codes // assoc. list of transponder codes
|
||||
var/codes_txt = "" // codes as set on map: "tag1;tag2" or "tag1=value;tag2=value"
|
||||
var/codes_txt // DEPRECATED codes as set on map: "tag1;tag2" or "tag1=value;tag2=value"
|
||||
var/list/codes = list() // assoc. list of transponder codes
|
||||
req_access = list(access_engine)
|
||||
|
||||
/obj/machinery/navbeacon/New()
|
||||
..()
|
||||
|
||||
set_codes()
|
||||
set_codes_from_txt(codes_txt)
|
||||
if(freq)
|
||||
warning("[src] at [x],[y],[z] has deprecated var freq=[freq]. Replace it with proper type.")
|
||||
|
||||
var/turf/T = loc
|
||||
hide(!T.is_plating())
|
||||
|
||||
// add beacon to MULE bot beacon list
|
||||
if(freq == 1400)
|
||||
if(!navbeacons)
|
||||
navbeacons = new()
|
||||
navbeacons += src
|
||||
|
||||
|
||||
spawn(5) // must wait for map loading to finish
|
||||
if(radio_controller)
|
||||
radio_controller.add_object(src, freq, RADIO_NAVBEACONS)
|
||||
navbeacons += src
|
||||
|
||||
// set the transponder codes assoc list from codes_txt
|
||||
/obj/machinery/navbeacon/proc/set_codes()
|
||||
// DEPRECATED - This is kept only for compatibilty with old map files! Do not use this!
|
||||
// Instead, you should replace the map instance with one of the appropriate navbeacon subtypes.
|
||||
// See the bottom of this file for a list of subtypes, make your own examples if your map needs more
|
||||
/obj/machinery/navbeacon/proc/set_codes_from_txt()
|
||||
if(!codes_txt)
|
||||
return
|
||||
warning("[src] at [x],[y],[z] in [get_area(src)] is using the deprecated 'codes_txt' mapping method. Replace it with proper type.")
|
||||
|
||||
codes = new()
|
||||
|
||||
codes = list()
|
||||
var/list/entries = splittext(codes_txt, ";") // entries are separated by semicolons
|
||||
|
||||
for(var/e in entries)
|
||||
var/index = findtext(e, "=") // format is "key=value"
|
||||
if(index)
|
||||
@@ -56,6 +49,8 @@ var/global/list/navbeacons // no I don't like putting this in, but it will do
|
||||
else
|
||||
codes[e] = "1"
|
||||
|
||||
/obj/machinery/navbeacon/hides_under_flooring()
|
||||
return 1
|
||||
|
||||
// called when turf state changes
|
||||
// hide the object if turf is intact
|
||||
@@ -73,38 +68,6 @@ var/global/list/navbeacons // no I don't like putting this in, but it will do
|
||||
else
|
||||
icon_state = "[state]"
|
||||
|
||||
|
||||
// look for a signal of the form "findbeacon=X"
|
||||
// where X is any
|
||||
// or the location
|
||||
// or one of the set transponder keys
|
||||
// if found, return a signal
|
||||
/obj/machinery/navbeacon/receive_signal(datum/signal/signal)
|
||||
|
||||
var/request = signal.data["findbeacon"]
|
||||
if(request && ((request in codes) || request == "any" || request == location))
|
||||
spawn(1)
|
||||
post_signal()
|
||||
|
||||
// return a signal giving location and transponder codes
|
||||
|
||||
/obj/machinery/navbeacon/proc/post_signal()
|
||||
|
||||
var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq)
|
||||
|
||||
if(!frequency) return
|
||||
|
||||
var/datum/signal/signal = new()
|
||||
signal.source = src
|
||||
signal.transmission_method = 1
|
||||
signal.data["beacon"] = location
|
||||
|
||||
for(var/key in codes)
|
||||
signal.data[key] = codes[key]
|
||||
|
||||
frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS)
|
||||
|
||||
|
||||
/obj/machinery/navbeacon/attackby(var/obj/item/I, var/mob/user)
|
||||
var/turf/T = loc
|
||||
if(!T.is_plating())
|
||||
@@ -117,7 +80,7 @@ var/global/list/navbeacons // no I don't like putting this in, but it will do
|
||||
|
||||
updateicon()
|
||||
|
||||
else if(istype(I, /obj/item/weapon/card/id)||istype(I, /obj/item/device/pda))
|
||||
else if(I.GetID())
|
||||
if(open)
|
||||
if(allowed(user))
|
||||
locked = !locked
|
||||
@@ -153,8 +116,7 @@ var/global/list/navbeacons // no I don't like putting this in, but it will do
|
||||
|
||||
if(locked && !ai)
|
||||
t = {"<TT><B>Navigation Beacon</B><HR><BR>
|
||||
<i>(swipe card to unlock controls)</i><BR>
|
||||
Frequency: [format_frequency(freq)]<BR><HR>
|
||||
<i>(swipe card to unlock controls)</i><BR><HR>
|
||||
Location: [location ? location : "(none)"]</A><BR>
|
||||
Transponder Codes:<UL>"}
|
||||
|
||||
@@ -165,14 +127,7 @@ Transponder Codes:<UL>"}
|
||||
else
|
||||
|
||||
t = {"<TT><B>Navigation Beacon</B><HR><BR>
|
||||
<i>(swipe card to lock controls)</i><BR>
|
||||
Frequency:
|
||||
<A href='byond://?src=\ref[src];freq=-10'>-</A>
|
||||
<A href='byond://?src=\ref[src];freq=-2'>-</A>
|
||||
[format_frequency(freq)]
|
||||
<A href='byond://?src=\ref[src];freq=2'>+</A>
|
||||
<A href='byond://?src=\ref[src];freq=10'>+</A><BR>
|
||||
<HR>
|
||||
<i>(swipe card to lock controls)</i><BR><HR>
|
||||
Location: <A href='byond://?src=\ref[src];locedit=1'>[location ? location : "(none)"]</A><BR>
|
||||
Transponder Codes:<UL>"}
|
||||
|
||||
@@ -195,11 +150,7 @@ Transponder Codes:<UL>"}
|
||||
if(open && !locked)
|
||||
usr.set_machine(src)
|
||||
|
||||
if(href_list["freq"])
|
||||
freq = sanitize_frequency(freq + text2num(href_list["freq"]))
|
||||
updateDialog()
|
||||
|
||||
else if(href_list["locedit"])
|
||||
if(href_list["locedit"])
|
||||
var/newloc = sanitize(input("Enter New Location", "Navigation Beacon", location) as text|null)
|
||||
if(newloc)
|
||||
location = newloc
|
||||
@@ -248,6 +199,41 @@ Transponder Codes:<UL>"}
|
||||
|
||||
/obj/machinery/navbeacon/Destroy()
|
||||
navbeacons.Remove(src)
|
||||
if(radio_controller)
|
||||
radio_controller.remove_object(src, freq)
|
||||
..()
|
||||
|
||||
|
||||
//
|
||||
// Nav Beacon Mapping
|
||||
// These subtypes are what you should actually put into maps! they will make your life much easier.
|
||||
//
|
||||
// Developer Note: navbeacons do not HAVE to use these subtypes. They are purely for mapping convenience.
|
||||
// You can feel free to construct them in-game as just /obj/machinery/navbeacon and they will work just
|
||||
// fine, and you can define your own specific types for every instance on map if you want (BayStation does)
|
||||
// This design is a compromise that means you can do mapping without every single one being its own type
|
||||
// but with it still being easy to map ~ Leshana
|
||||
//
|
||||
|
||||
// Mulebot delivery destinations
|
||||
|
||||
/obj/machinery/navbeacon/delivery/north
|
||||
codes = list("delivery" = 1, "dir" = NORTH)
|
||||
|
||||
/obj/machinery/navbeacon/delivery/south
|
||||
codes = list("delivery" = 1, "dir" = SOUTH)
|
||||
|
||||
/obj/machinery/navbeacon/delivery/east
|
||||
codes = list("delivery" = 1, "dir" = EAST)
|
||||
|
||||
/obj/machinery/navbeacon/delivery/west
|
||||
codes = list("delivery" = 1, "dir" = WEST)
|
||||
|
||||
|
||||
// For part of the patrol route
|
||||
// You MUST set "location"
|
||||
// You MUST set "next_patrol"
|
||||
/obj/machinery/navbeacon/patrol
|
||||
var/next_patrol
|
||||
|
||||
/obj/machinery/navbeacon/patrol/New()
|
||||
codes = list("patrol" = 1, "next_patrol" = next_patrol)
|
||||
..()
|
||||
|
||||
@@ -441,7 +441,7 @@ var/list/turret_icons
|
||||
else
|
||||
take_damage(initial(health) * 8) //should instakill most turrets
|
||||
if(3)
|
||||
take_damage(initial(health) * 8 / 3)
|
||||
take_damage(initial(health) * 8 / 3) //Level 4 is too weak to bother turrets
|
||||
|
||||
/obj/machinery/porta_turret/proc/die() //called when the turret dies, ie, health <= 0
|
||||
health = 0
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
proc/shock()
|
||||
var/obj/mecha/M = in_mecha()
|
||||
if(M)
|
||||
M.emp_act(2)
|
||||
M.emp_act(4)
|
||||
qdel(src)
|
||||
|
||||
proc/get_mecha_log()
|
||||
|
||||
@@ -333,7 +333,7 @@ steam.start() -- spawns the effect
|
||||
spawn(0)
|
||||
var/turf/T = get_turf(src.holder)
|
||||
if(T != src.oldposition)
|
||||
if(istype(T, /turf/simulated))
|
||||
if(isturf(T))
|
||||
var/obj/effect/effect/ion_trails/I = PoolOrNew(/obj/effect/effect/ion_trails, src.oldposition)
|
||||
src.oldposition = T
|
||||
I.set_dir(src.holder.dir)
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// This artificially splits a ZAS zone, useful if you wish to prevent massive super-zones which can cause lag.
|
||||
/obj/effect/zone_divider
|
||||
name = "zone divider"
|
||||
icon = 'icons/mob/screen1.dmi'
|
||||
icon_state = "x3"
|
||||
invisibility = 101 //nope, can't see this
|
||||
anchored = 1
|
||||
density = 0
|
||||
opacity = 0
|
||||
|
||||
/obj/effect/zone_divider/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
||||
// Special case to prevent us from being part of a zone during the first air master tick.
|
||||
// We must merge ourselves into a zone on next tick. This will cause a bit of lag on
|
||||
// startup, but it can't really be helped you know?
|
||||
if(air_master && air_master.current_cycle == 0)
|
||||
spawn(1)
|
||||
air_master.mark_for_update(get_turf(src))
|
||||
return 0
|
||||
return !air_group // Anything except zones can pass
|
||||
|
||||
@@ -4,17 +4,17 @@
|
||||
|
||||
// #define EMPDEBUG 10
|
||||
|
||||
proc/empulse(turf/epicenter, heavy_range, light_range, log=0)
|
||||
proc/empulse(turf/epicenter, first_range, second_range, third_range, fourth_range, log=0)
|
||||
if(!epicenter) return
|
||||
|
||||
if(!istype(epicenter, /turf))
|
||||
epicenter = get_turf(epicenter.loc)
|
||||
|
||||
if(log)
|
||||
message_admins("EMP with size ([heavy_range], [light_range]) in area [epicenter.loc.name] ")
|
||||
log_game("EMP with size ([heavy_range], [light_range]) in area [epicenter.loc.name] ")
|
||||
message_admins("EMP with size ([first_range], [second_range], [third_range], [fourth_range]) in area [epicenter.loc.name] ")
|
||||
log_game("EMP with size ([first_range], [second_range], [third_range], [fourth_range]) in area [epicenter.loc.name] ")
|
||||
|
||||
if(heavy_range > 1)
|
||||
if(first_range > 1)
|
||||
var/obj/effect/overlay/pulse = PoolOrNew(/obj/effect/overlay, epicenter)
|
||||
pulse.icon = 'icons/effects/effects.dmi'
|
||||
pulse.icon_state = "emppulse"
|
||||
@@ -23,28 +23,50 @@ proc/empulse(turf/epicenter, heavy_range, light_range, log=0)
|
||||
spawn(20)
|
||||
qdel(pulse)
|
||||
|
||||
if(heavy_range > light_range)
|
||||
light_range = heavy_range
|
||||
if(first_range > second_range)
|
||||
second_range = first_range
|
||||
if(second_range > third_range)
|
||||
third_range = second_range
|
||||
if(third_range > fourth_range)
|
||||
fourth_range = third_range
|
||||
|
||||
for(var/mob/M in range(heavy_range, epicenter))
|
||||
for(var/mob/M in range(first_range, epicenter))
|
||||
M << 'sound/effects/EMPulse.ogg'
|
||||
|
||||
for(var/atom/T in range(light_range, epicenter))
|
||||
for(var/atom/T in range(fourth_range, epicenter))
|
||||
#ifdef EMPDEBUG
|
||||
var/time = world.timeofday
|
||||
#endif
|
||||
var/distance = get_dist(epicenter, T)
|
||||
if(distance < 0)
|
||||
distance = 0
|
||||
if(distance < heavy_range)
|
||||
//Worst effects, really hurts
|
||||
if(distance < first_range)
|
||||
T.emp_act(1)
|
||||
else if(distance == heavy_range)
|
||||
else if(distance == first_range)
|
||||
if(prob(50))
|
||||
T.emp_act(1)
|
||||
else
|
||||
T.emp_act(2)
|
||||
else if(distance <= light_range)
|
||||
//Slightly less painful
|
||||
else if(distance <= second_range)
|
||||
T.emp_act(2)
|
||||
else if(distance == second_range)
|
||||
if(prob(50))
|
||||
T.emp_act(2)
|
||||
else
|
||||
T.emp_act(3)
|
||||
//Even less slightly less painful
|
||||
else if(distance <= third_range)
|
||||
T.emp_act(3)
|
||||
else if(distance == third_range)
|
||||
if(prob(50))
|
||||
T.emp_act(2)
|
||||
else
|
||||
T.emp_act(3)
|
||||
//This should be more or less harmless
|
||||
else if(distance <= fourth_range)
|
||||
T.emp_act(4)
|
||||
#ifdef EMPDEBUG
|
||||
if((world.timeofday - time) >= EMPDEBUG)
|
||||
log_and_message_admins("EMPDEBUG: [T.name] - [T.type] - took [world.timeofday - time]ds to process emp_act()!")
|
||||
|
||||
@@ -998,7 +998,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
|
||||
M.apply_damage( rand(30,60) , BURN)
|
||||
message += "You feel a searing heat! Your [P] is burning!"
|
||||
if(i>=20 && i<=25) //EMP
|
||||
empulse(P.loc, 3, 6, 1)
|
||||
empulse(P.loc, 1, 2, 4, 6, 1)
|
||||
message += "Your [P] emits a wave of electromagnetic energy!"
|
||||
if(i>=25 && i<=40) //Smoke
|
||||
var/datum/effect/effect/system/smoke_spread/chem/S = new /datum/effect/effect/system/smoke_spread/chem
|
||||
|
||||
@@ -213,6 +213,17 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
|
||||
update_icon()
|
||||
ui_interact(user)
|
||||
|
||||
// Proc: MouseDrop()
|
||||
//Same thing PDAs do
|
||||
/obj/item/device/communicator/MouseDrop(obj/over_object as obj)
|
||||
var/mob/M = usr
|
||||
if (!(src.loc == usr) || (src.loc && src.loc.loc == usr))
|
||||
return
|
||||
if(!istype(over_object, /obj/screen))
|
||||
return attack_self(M)
|
||||
return
|
||||
|
||||
|
||||
// Proc: attack_ghost()
|
||||
// Parameters: 1 (user - the ghost clicking on the device)
|
||||
// Description: Recreates the known_devices list, so that the ghost looking at the device can see themselves, then calls ..() so that NanoUI appears.
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
//Universal translator
|
||||
/obj/item/device/universal_translator
|
||||
name = "handheld translator"
|
||||
desc = "This handy device appears to translate the languages it hears into onscreen text for a user."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "translator"
|
||||
w_class = ITEMSIZE_SMALL
|
||||
origin_tech = list(TECH_DATA = 3, TECH_ENGINEERING = 3)
|
||||
var/mult_icons = 1 //Changes sprite when it translates
|
||||
var/visual = 1 //If you need to see to get the message
|
||||
var/audio = 0 //If you need to hear to get the message
|
||||
var/listening = 0
|
||||
var/datum/language/langset
|
||||
|
||||
/obj/item/device/universal_translator/attack_self(mob/user)
|
||||
if(!listening) //Turning ON
|
||||
langset = input(user,"Translate to which of your languages?","Language Selection") as null|anything in user.languages
|
||||
if(langset)
|
||||
if(langset && ((langset.flags & NONVERBAL) || (langset.flags & HIVEMIND)))
|
||||
to_chat(user, "<span class='warning'>\The [src] cannot output that language.</span>")
|
||||
return
|
||||
else
|
||||
listening = 1
|
||||
listening_objects |= src
|
||||
if(mult_icons)
|
||||
icon_state = "[initial(icon_state)]1"
|
||||
to_chat(user, "<span class='notice'>You enable \the [src], translating into [langset.name].</span>")
|
||||
else //Turning OFF
|
||||
listening = 0
|
||||
listening_objects -= src
|
||||
langset = null
|
||||
icon_state = "[initial(icon_state)]"
|
||||
to_chat(user, "<span class='notice'>You disable \the [src].</span>")
|
||||
|
||||
/obj/item/device/universal_translator/hear_talk(var/mob/speaker, var/message, var/vrb, var/datum/language/language)
|
||||
if(!listening || !istype(speaker))
|
||||
return
|
||||
|
||||
//Show the "I heard something" animation.
|
||||
if(mult_icons)
|
||||
flick("[initial(icon_state)]2",src)
|
||||
|
||||
//Handheld or pocket only.
|
||||
if(!isliving(loc))
|
||||
return
|
||||
|
||||
var/mob/living/L = loc
|
||||
|
||||
if (language && (language.flags & NONVERBAL))
|
||||
return //Not gonna translate sign language
|
||||
|
||||
if (visual && ((L.sdisabilities & BLIND) || L.eye_blind))
|
||||
return //Can't see the screen, don't get the message
|
||||
|
||||
if (audio && ((L.sdisabilities & DEAF) || L.ear_deaf))
|
||||
return //Can't hear the translation, don't get the message
|
||||
|
||||
//Only translate if they can't understand, otherwise pointlessly spammy
|
||||
//I'll just assume they don't look at the screen in that case
|
||||
|
||||
//They don't understand the spoken language we're translating FROM
|
||||
if(!L.say_understands(speaker,language))
|
||||
//They understand the output language
|
||||
if(L.say_understands(null,langset))
|
||||
to_chat(L, "<i><b>[src]</b> translates, </i>\"<span class='[langset.colour]'>[message]</span>\"")
|
||||
|
||||
//They don't understand the output language
|
||||
else
|
||||
to_chat(L, "<i><b>[src]</b> translates, </i>\"<span class='[langset.colour]'>[langset.scramble(message)]</span>\"")
|
||||
|
||||
//Let's try an ear-worn version
|
||||
/obj/item/device/universal_translator/ear
|
||||
name = "translator earpiece"
|
||||
desc = "This handy device appears to translate the languages it hears into another language for a user."
|
||||
icon_state = "earpiece"
|
||||
w_class = ITEMSIZE_TINY
|
||||
slot_flags = SLOT_EARS
|
||||
visual = 0
|
||||
audio = 1
|
||||
@@ -3,12 +3,14 @@
|
||||
icon_state = "emp"
|
||||
item_state = "empgrenade"
|
||||
origin_tech = list(TECH_MATERIAL = 2, TECH_MAGNET = 3)
|
||||
var/emp_heavy = 4
|
||||
var/emp_light = 10
|
||||
var/emp_heavy = 2
|
||||
var/emp_med = 4
|
||||
var/emp_light = 7
|
||||
var/emp_long = 10
|
||||
|
||||
prime()
|
||||
..()
|
||||
if(empulse(src, emp_heavy, emp_light))
|
||||
if(empulse(src, emp_heavy, emp_med, emp_light, emp_long))
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
@@ -18,4 +20,6 @@
|
||||
icon_state = "lyemp"
|
||||
origin_tech = list(TECH_MATERIAL = 2, TECH_MAGNET = 3)
|
||||
emp_heavy = 1
|
||||
emp_light = 4
|
||||
emp_med = 2
|
||||
emp_light = 3
|
||||
emp_long = 4
|
||||
@@ -101,6 +101,10 @@ Implant Specifics:<BR>"}
|
||||
meltdown()
|
||||
if(2)
|
||||
delay = rand(5*60*10,15*60*10) //from 5 to 15 minutes of free time
|
||||
if(3)
|
||||
delay = rand(2*60*10,5*60*10) //from 2 to 5 minutes of free time
|
||||
if(4)
|
||||
delay = rand(0.5*60*10,1*60*10) //from .5 to 1 minutes of free time
|
||||
|
||||
spawn(delay)
|
||||
malfunction--
|
||||
@@ -227,10 +231,22 @@ Implant Specifics:<BR>"}
|
||||
return
|
||||
malfunction = MALFUNCTION_TEMPORARY
|
||||
switch (severity)
|
||||
if (2.0) //Weak EMP will make implant tear limbs off.
|
||||
if (4) //Weak EMP will make implant tear limbs off.
|
||||
if (prob(25))
|
||||
small_boom()
|
||||
if (3) //Weak EMP will make implant tear limbs off.
|
||||
if (prob(50))
|
||||
small_boom()
|
||||
if (1.0) //strong EMP will melt implant either making it go off, or disarming it
|
||||
if (2) //strong EMP will melt implant either making it go off, or disarming it
|
||||
if (prob(70))
|
||||
if (prob(75))
|
||||
small_boom()
|
||||
else
|
||||
if (prob(13))
|
||||
activate() //chance of bye bye
|
||||
else
|
||||
meltdown() //chance of implant disarming
|
||||
if (1) //strong EMP will melt implant either making it go off, or disarming it
|
||||
if (prob(70))
|
||||
if (prob(50))
|
||||
small_boom()
|
||||
@@ -320,7 +336,13 @@ the implant may become unstable and either pre-maturely inject the subject or si
|
||||
if(prob(60))
|
||||
activate(20)
|
||||
if(2)
|
||||
if(prob(30))
|
||||
if(prob(40))
|
||||
activate(20)
|
||||
if(3)
|
||||
if(prob(40))
|
||||
activate(5)
|
||||
if(4)
|
||||
if(prob(20))
|
||||
activate(5)
|
||||
|
||||
spawn(20)
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
/obj/item/weapon/tank/vox //Can't be a child of phoron or the gas amount gets screwey.
|
||||
name = "phoron tank"
|
||||
desc = "Contains dangerous phoron. Do not inhale. Warning: extremely flammable."
|
||||
icon_state = "oxygen_fr"
|
||||
icon_state = "phoron_vox"
|
||||
gauge_icon = null
|
||||
flags = CONDUCT
|
||||
distribute_pressure = ONE_ATMOSPHERE*O2STANDARD
|
||||
@@ -209,4 +209,4 @@
|
||||
/obj/item/weapon/tank/nitrogen/examine(mob/user)
|
||||
if(..(user, 0) && air_contents.gas["nitrogen"] < 10)
|
||||
user << text("<span class='danger'>The meter on \the [src] indicates you are almost out of nitrogen!</span>")
|
||||
//playsound(user, 'sound/effects/alert.ogg', 50, 1)
|
||||
//playsound(user, 'sound/effects/alert.ogg', 50, 1)
|
||||
|
||||
@@ -142,6 +142,7 @@
|
||||
new /obj/item/clothing/suit/storage/toggle/labcoat/emt(src)
|
||||
new /obj/item/device/radio/headset/headset_med/alt(src)
|
||||
new /obj/item/weapon/cartridge/medical(src)
|
||||
new /obj/item/weapon/storage/briefcase/inflatable(src)
|
||||
new /obj/item/device/flashlight(src)
|
||||
new /obj/item/weapon/tank/emergency/oxygen/engi(src)
|
||||
new /obj/item/clothing/glasses/hud/health(src)
|
||||
|
||||
@@ -283,9 +283,9 @@
|
||||
/obj/structure/closet/crate/rcd
|
||||
name = "\improper RCD crate"
|
||||
desc = "A crate with rapid construction device."
|
||||
icon_state = "crate"
|
||||
icon_opened = "crateopen"
|
||||
icon_closed = "crate"
|
||||
icon_state = "engi_crate"
|
||||
icon_opened = "engi_crateopen"
|
||||
icon_closed = "engi_crate"
|
||||
|
||||
/obj/structure/closet/crate/rcd/New()
|
||||
..()
|
||||
@@ -427,6 +427,20 @@
|
||||
icon_opened = "hydrosecurecrateopen"
|
||||
icon_closed = "hydrosecurecrate"
|
||||
|
||||
/obj/structure/closet/crate/secure/engineering
|
||||
desc = "A crate with a lock on it, painted in the scheme of the station's engineers."
|
||||
name = "secure engineering crate"
|
||||
icon_state = "engi_secure_crate"
|
||||
icon_opened = "engi_secure_crateopen"
|
||||
icon_closed = "engi_secure_crate"
|
||||
|
||||
/obj/structure/closet/crate/secure/science
|
||||
name = "secure science crate"
|
||||
desc = "A crate with a lock on it, painted in the scheme of the station's scientists."
|
||||
icon_state = "scisecurecrate"
|
||||
icon_opened = "scisecurecrateopen"
|
||||
icon_closed = "scisecurecrate"
|
||||
|
||||
/obj/structure/closet/crate/secure/bin
|
||||
name = "secure bin"
|
||||
desc = "A secure bin."
|
||||
@@ -499,6 +513,23 @@
|
||||
icon_opened = "largermetalopen"
|
||||
icon_closed = "largermetal"
|
||||
|
||||
/obj/structure/closet/crate/engineering
|
||||
name = "engineering crate"
|
||||
icon_state = "engi_crate"
|
||||
icon_opened = "engi_crateopen"
|
||||
icon_closed = "engi_crate"
|
||||
|
||||
/obj/structure/closet/crate/engineering/electrical
|
||||
icon_state = "engi_e_crate"
|
||||
icon_opened = "engi_crateopen"
|
||||
icon_closed = "engi_e_crate"
|
||||
|
||||
/obj/structure/closet/crate/science
|
||||
name = "science crate"
|
||||
icon_state = "scicrate"
|
||||
icon_opened = "scicrateopen"
|
||||
icon_closed = "scicrate"
|
||||
|
||||
/obj/structure/closet/crate/hydroponics
|
||||
name = "hydroponics crate"
|
||||
desc = "All you need to destroy those pesky weeds and pests."
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
|
||||
/obj/structure/largecrate/animal/goat
|
||||
name = "goat crate"
|
||||
held_type = /mob/living/simple_animal/hostile/retaliate/goat
|
||||
held_type = /mob/living/simple_animal/retaliate/goat
|
||||
|
||||
/obj/structure/largecrate/animal/cat
|
||||
name = "cat carrier"
|
||||
|
||||
@@ -107,6 +107,16 @@
|
||||
airlock_type = "/highsecurity"
|
||||
glass = -1
|
||||
|
||||
/obj/structure/door_assembly/door_assembly_voidcraft
|
||||
base_icon_state = "voidcraft"
|
||||
base_name = "voidcraft hatch"
|
||||
airlock_type = "/voidcraft"
|
||||
glass = -1
|
||||
|
||||
/obj/structure/door_assembly/door_assembly_voidcraft/vertical
|
||||
base_icon_state = "voidcraft_vertical"
|
||||
airlock_type = "/voidcraft/vertical"
|
||||
|
||||
/obj/structure/door_assembly/multi_tile
|
||||
icon = 'icons/obj/doors/door_assembly2x1.dmi'
|
||||
dir = EAST
|
||||
|
||||
@@ -17,7 +17,7 @@ var/list/floor_decals = list()
|
||||
/obj/effect/floor_decal/initialize()
|
||||
if(supplied_dir) set_dir(supplied_dir)
|
||||
var/turf/T = get_turf(src)
|
||||
if(istype(T, /turf/simulated/floor) || istype(T, /turf/unsimulated/floor))
|
||||
if(istype(T, /turf/simulated/floor) || istype(T, /turf/unsimulated/floor) || istype(T, /turf/simulated/shuttle/floor))
|
||||
var/cache_key = "[alpha]-[color]-[dir]-[icon_state]-[layer]"
|
||||
if(!floor_decals[cache_key])
|
||||
var/image/I = image(icon = src.icon, icon_state = src.icon_state, dir = src.dir)
|
||||
|
||||
@@ -19,6 +19,34 @@
|
||||
density = 1
|
||||
blocks_air = 1
|
||||
|
||||
/turf/simulated/shuttle/wall/voidcraft
|
||||
name = "voidcraft wall"
|
||||
icon = 'icons/turf/voidcraft_walls.dmi'
|
||||
icon_state = "voidcraft_wall_alone"
|
||||
var/stripe_color = null // If set, generates a colored stripe overlay. Accepts #XXXXXX as input.
|
||||
|
||||
/turf/simulated/shuttle/wall/voidcraft/red
|
||||
stripe_color = "#FF0000"
|
||||
|
||||
/turf/simulated/shuttle/wall/voidcraft/blue
|
||||
stripe_color = "#0000FF"
|
||||
|
||||
/turf/simulated/shuttle/wall/voidcraft/green
|
||||
stripe_color = "#00FF00"
|
||||
|
||||
/turf/simulated/shuttle/wall/voidcraft/New()
|
||||
..()
|
||||
update_icon()
|
||||
|
||||
/turf/simulated/shuttle/wall/voidcraft/update_icon()
|
||||
var/list/icon_states = icon_states(src.icon)
|
||||
if(("[icon_state]_stripe" in icon_states) && stripe_color)
|
||||
overlays.Cut()
|
||||
var/image/I = image(icon = src.icon, dir = src.dir, icon_state = "[icon_state]_stripe")
|
||||
if(stripe_color)
|
||||
I.color = stripe_color
|
||||
overlays.Add(I)
|
||||
|
||||
/turf/simulated/shuttle/floor
|
||||
name = "floor"
|
||||
icon_state = "floor"
|
||||
@@ -41,4 +69,15 @@
|
||||
oxygen = 0
|
||||
nitrogen = MOLES_N2STANDARD + MOLES_O2STANDARD
|
||||
|
||||
/turf/simulated/shuttle/floor/voidcraft
|
||||
name = "voidcraft tiles"
|
||||
icon_state = "voidcraft_floor"
|
||||
|
||||
/turf/simulated/shuttle/floor/voidcraft/dark
|
||||
name = "voidcraft tiles"
|
||||
icon_state = "voidcraft_floor_dark"
|
||||
|
||||
/turf/simulated/shuttle/floor/voidcraft/light
|
||||
name = "voidcraft tiles"
|
||||
icon_state = "voidcraft_floor_light"
|
||||
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
name = "dirt"
|
||||
desc = "Quite dirty!"
|
||||
icon_state = "dirt-dark"
|
||||
edge_blending_priority = 1
|
||||
edge_blending_priority = 2
|
||||
turf_layers = list(/turf/simulated/floor/outdoors/rocks)
|
||||
@@ -6,7 +6,7 @@ var/list/grass_types = list(
|
||||
/turf/simulated/floor/outdoors/grass
|
||||
name = "grass"
|
||||
icon_state = "grass"
|
||||
edge_blending_priority = 3
|
||||
edge_blending_priority = 4
|
||||
turf_layers = list(
|
||||
/turf/simulated/floor/outdoors/rocks,
|
||||
/turf/simulated/floor/outdoors/dirt
|
||||
@@ -16,8 +16,14 @@ var/list/grass_types = list(
|
||||
/turf/simulated/floor/outdoors/grass/sif
|
||||
name = "growth"
|
||||
icon_state = "grass_sif"
|
||||
edge_blending_priority = 3
|
||||
edge_blending_priority = 4
|
||||
grass_chance = 0
|
||||
var/tree_chance = 2
|
||||
|
||||
/turf/simulated/floor/outdoors/grass/sif/New()
|
||||
if(tree_chance && prob(tree_chance))
|
||||
new /obj/structure/flora/tree/sif(src)
|
||||
..()
|
||||
|
||||
/turf/simulated/floor/outdoors/grass/New()
|
||||
if(prob(50))
|
||||
@@ -33,10 +39,11 @@ var/list/grass_types = list(
|
||||
name = "thick grass"
|
||||
icon_state = "grass-dark"
|
||||
grass_chance = 80
|
||||
//tree_prob = 20
|
||||
edge_blending_priority = 4
|
||||
//tree_chance = 20
|
||||
edge_blending_priority = 5
|
||||
|
||||
/turf/simulated/floor/outdoors/grass/sif/forest
|
||||
name = "thick growth"
|
||||
icon_state = "grass_sif_dark"
|
||||
edge_blending_priority = 4
|
||||
edge_blending_priority = 5
|
||||
tree_chance = 10
|
||||
@@ -55,7 +55,7 @@ var/list/outdoor_turfs = list()
|
||||
/turf/simulated/floor/outdoors/mud
|
||||
name = "grass"
|
||||
icon_state = "mud_dark"
|
||||
edge_blending_priority = 2
|
||||
edge_blending_priority = 3
|
||||
|
||||
/turf/simulated/floor/outdoors/rocks
|
||||
name = "rocks"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/turf/simulated/floor/outdoors/snow
|
||||
name = "snow"
|
||||
icon_state = "snow"
|
||||
edge_blending_priority = 5
|
||||
edge_blending_priority = 6
|
||||
movement_cost = 2
|
||||
turf_layers = list(
|
||||
/turf/simulated/floor/outdoors/rocks,
|
||||
|
||||
@@ -45,4 +45,10 @@
|
||||
..(newloc,"titanium")
|
||||
|
||||
/turf/simulated/wall/durasteel/New(var/newloc)
|
||||
..(newloc,"durasteel", "durasteel")
|
||||
..(newloc,"durasteel", "durasteel")
|
||||
|
||||
/turf/simulated/wall/wood/New(var/newloc)
|
||||
..(newloc,"wood")
|
||||
|
||||
/turf/simulated/wall/sifwood/New(var/newloc)
|
||||
..(newloc,"alien wood")
|
||||
@@ -3,12 +3,12 @@
|
||||
name = "shallow water"
|
||||
desc = "A body of water. It seems shallow enough to walk through, if needed."
|
||||
icon = 'icons/turf/outdoors.dmi'
|
||||
icon_state = "water_shallow"
|
||||
icon_state = "seashallow" // So it shows up in the map editor as water.
|
||||
var/water_state = "water_shallow"
|
||||
var/under_state = "rock"
|
||||
edge_blending_priority = -1
|
||||
movement_cost = 4
|
||||
outdoors = TRUE
|
||||
var/movement_message = "You are slowed considerably from the water as you move across it." // Displayed to mobs crossing from one water tile to another.
|
||||
var/depth = 1 // Higher numbers indicates deeper water.
|
||||
|
||||
/turf/simulated/floor/water/New()
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
/turf/simulated/floor/water/update_icon()
|
||||
..() // To get the edges. This also gets rid of other overlays so it needs to go first.
|
||||
icon_state = water_state
|
||||
var/image/floorbed_sprite = image(icon = 'icons/turf/outdoors.dmi', icon_state = under_state)
|
||||
underlays.Add(floorbed_sprite)
|
||||
update_icon_edge()
|
||||
@@ -43,8 +44,6 @@
|
||||
L.update_water()
|
||||
if(!istype(oldloc, /turf/simulated/floor/water))
|
||||
to_chat(L, "<span class='warning'>You get drenched in water from entering \the [src]!</span>")
|
||||
else
|
||||
to_chat(L, "<span class='warning'>[movement_message]</span>")
|
||||
AM.water_act(5)
|
||||
..()
|
||||
|
||||
@@ -63,7 +62,6 @@
|
||||
under_state = "abyss"
|
||||
edge_blending_priority = -2
|
||||
movement_cost = 8
|
||||
movement_message = "You swim forwards."
|
||||
depth = 2
|
||||
|
||||
/turf/simulated/floor/water/pool
|
||||
@@ -72,6 +70,11 @@
|
||||
under_state = "pool"
|
||||
outdoors = FALSE
|
||||
|
||||
/turf/simulated/floor/water/deep/pool
|
||||
name = "deep pool"
|
||||
desc = "Don't worry, it's not closed."
|
||||
outdoors = FALSE
|
||||
|
||||
/mob/living/proc/can_breathe_water()
|
||||
return FALSE
|
||||
|
||||
@@ -93,4 +96,33 @@
|
||||
/mob/living/water_act(amount)
|
||||
adjust_fire_stacks(amount * 5)
|
||||
for(var/atom/movable/AM in contents)
|
||||
AM.water_act(amount)
|
||||
AM.water_act(amount)
|
||||
|
||||
var/list/shoreline_icon_cache = list()
|
||||
|
||||
/turf/simulated/floor/water/shoreline
|
||||
name = "shoreline"
|
||||
desc = "The waves look calm and inviting."
|
||||
icon_state = "shoreline"
|
||||
water_state = "rock" // Water gets generated as an overlay in update_icon()
|
||||
depth = 0
|
||||
|
||||
/turf/simulated/floor/water/shoreline/corner
|
||||
icon_state = "shorelinecorner"
|
||||
|
||||
// Water sprites are really annoying, so let BYOND sort it out.
|
||||
/turf/simulated/floor/water/shoreline/update_icon()
|
||||
underlays.Cut()
|
||||
overlays.Cut()
|
||||
..() // Get the underlay first.
|
||||
var/cache_string = "[initial(icon_state)]_[water_state]_[dir]"
|
||||
if(cache_string in shoreline_icon_cache) // Check to see if an icon already exists.
|
||||
overlays += shoreline_icon_cache[cache_string]
|
||||
else // If not, make one, but only once.
|
||||
var/icon/shoreline_water = icon(src.icon, "shoreline_water", src.dir)
|
||||
var/icon/shoreline_subtract = icon(src.icon, "[initial(icon_state)]_subtract", src.dir)
|
||||
shoreline_water.Blend(shoreline_subtract,ICON_SUBTRACT)
|
||||
|
||||
shoreline_icon_cache[cache_string] = shoreline_water
|
||||
overlays += shoreline_icon_cache[cache_string]
|
||||
|
||||
|
||||
@@ -161,7 +161,8 @@ var/list/admin_verbs_server = list(
|
||||
/client/proc/toggle_random_events,
|
||||
/client/proc/check_customitem_activity,
|
||||
/client/proc/nanomapgen_DumpImage,
|
||||
/client/proc/modify_server_news
|
||||
/client/proc/modify_server_news,
|
||||
/client/proc/recipe_dump
|
||||
)
|
||||
var/list/admin_verbs_debug = list(
|
||||
/client/proc/getruntimelog, //allows us to access runtime logs to somebody,
|
||||
|
||||
@@ -471,8 +471,10 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
antag_data.place_mob(new_character)
|
||||
|
||||
//If desired, apply equipment.
|
||||
if(equipment && charjob)
|
||||
job_master.EquipRank(new_character, charjob, 1)
|
||||
if(equipment)
|
||||
if(charjob)
|
||||
job_master.EquipRank(new_character, charjob, 1)
|
||||
equip_custom_items(new_character)
|
||||
|
||||
//If desired, add records.
|
||||
if(records)
|
||||
@@ -637,14 +639,18 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
|
||||
var/heavy = input("Range of heavy pulse.", text("Input")) as num|null
|
||||
if(heavy == null) return
|
||||
var/med = input("Range of medium pulse.", text("Input")) as num|null
|
||||
if(med == null) return
|
||||
var/light = input("Range of light pulse.", text("Input")) as num|null
|
||||
if(light == null) return
|
||||
var/long = input("Range of long pulse.", text("Input")) as num|null
|
||||
if(long == null) return
|
||||
|
||||
if (heavy || light)
|
||||
if (heavy || med || light || long)
|
||||
|
||||
empulse(O, heavy, light)
|
||||
log_admin("[key_name(usr)] created an EM Pulse ([heavy],[light]) at ([O.x],[O.y],[O.z])")
|
||||
message_admins("[key_name_admin(usr)] created an EM PUlse ([heavy],[light]) at ([O.x],[O.y],[O.z])", 1)
|
||||
empulse(O, heavy, med, light, long)
|
||||
log_admin("[key_name(usr)] created an EM Pulse ([heavy],[med],[light],[long]) at ([O.x],[O.y],[O.z])")
|
||||
message_admins("[key_name_admin(usr)] created an EM PUlse ([heavy],[med],[light],[long]) at ([O.x],[O.y],[O.z])", 1)
|
||||
feedback_add_details("admin_verb","EMP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
return
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
//Cactus, Speedbird, Dynasty, oh my
|
||||
|
||||
var/datum/lore/atc_controller/atc = new/datum/lore/atc_controller
|
||||
|
||||
/datum/lore/atc_controller
|
||||
var/delay_max = 25 MINUTES //How long between ATC traffic, max. Default is 25 mins.
|
||||
var/delay_min = 40 MINUTES //How long between ATC traffic, min. Default is 40 mins.
|
||||
var/backoff_delay = 5 MINUTES //How long to back off if we can't talk and want to. Default is 5 mins.
|
||||
var/next_message //When the next message should happen in world.time
|
||||
var/force_chatter_type //Force a specific type of messages
|
||||
|
||||
var/squelched = 0 //If ATC is squelched currently
|
||||
|
||||
/datum/lore/atc_controller/New()
|
||||
spawn(10 SECONDS) //Lots of lag at the start of a shift.
|
||||
msg("New shift beginning, resuming traffic control.")
|
||||
next_message = world.time + rand(delay_min,delay_max)
|
||||
process()
|
||||
|
||||
/datum/lore/atc_controller/proc/process()
|
||||
if(world.time >= next_message)
|
||||
if(squelched)
|
||||
next_message = world.time + backoff_delay
|
||||
else
|
||||
next_message = world.time + rand(delay_min,delay_max)
|
||||
random_convo()
|
||||
|
||||
spawn(1 MINUTE) //We don't really need high-accuracy here.
|
||||
process()
|
||||
|
||||
/datum/lore/atc_controller/proc/msg(var/message,var/sender)
|
||||
ASSERT(message)
|
||||
global_announcer.autosay("[message]", sender ? sender : "[using_map.station_short] Space Control")
|
||||
|
||||
/datum/lore/atc_controller/proc/reroute_traffic(var/yes = 1)
|
||||
if(yes)
|
||||
if(!squelched)
|
||||
msg("Rerouting traffic away from [using_map.station_name].")
|
||||
squelched = 1
|
||||
else
|
||||
if(squelched)
|
||||
msg("Resuming normal traffic routing around [using_map.station_name].")
|
||||
squelched = 0
|
||||
|
||||
/datum/lore/atc_controller/proc/shift_ending(var/evac = 0)
|
||||
msg("Automated Shuttle departing [using_map.station_name] for [using_map.dock_name] on routine transfer route.","NT Automated Shuttle")
|
||||
sleep(5 SECONDS)
|
||||
msg("Automated Shuttle, cleared to complete routine transfer from [using_map.station_name] to [using_map.dock_name].")
|
||||
|
||||
/datum/lore/atc_controller/proc/random_convo()
|
||||
var/one = pick(loremaster.organizations) //These will pick an index, not an instance
|
||||
var/two = pick(loremaster.organizations)
|
||||
|
||||
var/datum/lore/organization/source = loremaster.organizations[one] //Resolve to the instances
|
||||
var/datum/lore/organization/dest = loremaster.organizations[two]
|
||||
|
||||
//Let's get some mission parameters
|
||||
var/owner = source.short_name //Use the short name
|
||||
var/prefix = pick(source.ship_prefixes) //Pick a random prefix
|
||||
var/mission = source.ship_prefixes[prefix] //The value of the prefix is the mission type that prefix does
|
||||
var/shipname = pick(source.ship_names) //Pick a random ship name to go with it
|
||||
var/destname = pick(dest.destination_names) //Pick a random holding from the destination
|
||||
|
||||
var/combined_name = "[owner] [prefix] [shipname]"
|
||||
var/alt_atc_names = list("[using_map.station_short] TraCon","[using_map.station_short] Control","[using_map.station_short] STC","[using_map.station_short] Airspace")
|
||||
var/wrong_atc_names = list("Sol Command","Orion Control", "[using_map.dock_name]")
|
||||
var/mission_noun = list("flight","mission","route")
|
||||
var/request_verb = list("requesting","calling for","asking for")
|
||||
|
||||
//First response is 'yes', second is 'no'
|
||||
var/requests = list("[using_map.station_short] transit clearance" = list("permission for transit granted", "permission for transit denied, contact regional on 953.5"),
|
||||
"planetary flight rules" = list("authorizing planetary flight rules", "denying planetary flight rules right now due to traffic"),
|
||||
"special flight rules" = list("authorizing special flight rules", "denying special flight rules, not allowed for your traffic class"),
|
||||
"current solar weather info" = list("sending you the relevant information via tightbeam", "cannot fulfill your request at the moment"),
|
||||
"nearby traffic info" = list("sending you current traffic info", "no available info in your area"),
|
||||
"remote telemetry data" = list("sending telemetry now", "no uplink from your ship, recheck your uplink and ask again"),
|
||||
"refueling information" = list("sending refueling information now", "no fuel for your ship class in this sector"),
|
||||
"a current system time sync" = list("sending time sync ping to you now", "your ship isn't compatible with our time sync, set time manually"),
|
||||
"current system starcharts" = list("transmitting current starcharts", "your request is queued, overloaded right now"),
|
||||
"permission to engage FTL" = list("permission to engage FTL granted, good day", "permission denied, wait for current traffic to pass"),
|
||||
"permission to transit system" = list("permission to transit granted, good day", "permission denied, wait for current traffic to pass"),
|
||||
"permission to depart system" = list("permission to depart granted, good day", "permission denied, wait for current traffic to pass"),
|
||||
"permission to enter system" = list("good day, permission to enter granted", "permission denied, wait for current traffic to pass"),
|
||||
)
|
||||
|
||||
//Random chance things for variety
|
||||
var/chatter_type = "normal"
|
||||
if(force_chatter_type)
|
||||
chatter_type = force_chatter_type
|
||||
else
|
||||
chatter_type = pick(2;"emerg",5;"wrong_freq","normal") //Be nice to have wrong_lang...
|
||||
|
||||
var/yes = prob(90) //Chance for them to say yes vs no
|
||||
|
||||
var/request = pick(requests)
|
||||
var/callname = pick(alt_atc_names)
|
||||
var/response = requests[request][yes ? 1 : 2] //1 is yes, 2 is no
|
||||
|
||||
var/full_request
|
||||
var/full_response
|
||||
var/full_closure
|
||||
|
||||
switch(chatter_type)
|
||||
if("wrong_freq")
|
||||
callname = pick(wrong_atc_names)
|
||||
full_request = "[callname], this is [combined_name] on a [mission] [pick(mission_noun)] to [destname], [pick(request_verb)] [request]."
|
||||
full_response = "[combined_name], this is [using_map.station_short] TraCon, wrong frequency. Switch to [rand(700,999)].[rand(1,9)]."
|
||||
full_closure = "[using_map.station_short] TraCon, understood, apologies."
|
||||
if("wrong_lang")
|
||||
//Can't implement this until autosay has language support
|
||||
if("emerg")
|
||||
var/problem = pick("hull breaches on multiple decks","unknown life forms on board","a drive about to go critical","asteroids impacting the hull","a total loss of engine power","people trying to board the ship")
|
||||
full_request = "This is [combined_name] declaring an emergency! We have [problem]!"
|
||||
full_response = "[combined_name], this is [using_map.station_short] TraCon, copy. Switch to emergency responder channel [rand(700,999)].[rand(1,9)]."
|
||||
full_closure = "[using_map.station_short] TraCon, okay, switching now."
|
||||
else
|
||||
full_request = "[callname], this is [combined_name] on a [mission] [pick(mission_noun)] to [destname], [pick(request_verb)] [request]."
|
||||
full_response = "[combined_name], this is [using_map.station_short] TraCon, [response]." //Station TraCon always calls themselves TraCon
|
||||
full_closure = "[using_map.station_short] TraCon, [yes ? "thank you" : "understood"], good day." //They always copy what TraCon called themselves in the end when they realize they said it wrong
|
||||
|
||||
//Ship sends request to ATC
|
||||
msg(full_request,"[prefix] [shipname]")
|
||||
sleep(5 SECONDS)
|
||||
//ATC sends response to ship
|
||||
msg(full_response)
|
||||
sleep(5 SECONDS)
|
||||
//Ship sends response to ATC
|
||||
msg(full_closure,"[prefix] [shipname]")
|
||||
return
|
||||
@@ -0,0 +1,13 @@
|
||||
//I AM THE LOREMASTER, ARE YOU THE GATEKEEPER?
|
||||
|
||||
var/datum/lore/loremaster/loremaster = new/datum/lore/loremaster
|
||||
|
||||
/datum/lore/loremaster
|
||||
var/list/organizations = list()
|
||||
|
||||
/datum/lore/loremaster/New()
|
||||
|
||||
var/list/paths = typesof(/datum/lore/organization) - /datum/lore/organization
|
||||
for(var/path in paths)
|
||||
var/datum/lore/organization/instance = new path()
|
||||
organizations[path] = instance
|
||||
@@ -0,0 +1,326 @@
|
||||
//Datums for different companies that can be used by busy_space
|
||||
/datum/lore/organization
|
||||
var/name = "" // Organization's name
|
||||
var/short_name = "" // Organization's shortname (NanoTrasen for "NanoTrasen Incorporated")
|
||||
var/desc = "" // One or two paragraph description of the organization, but only current stuff. Currently unused.
|
||||
var/history = "" // Historical discription of the organization's origins Currently unused.
|
||||
var/work = "" // Short description of their work, eg "an arms manufacturer"
|
||||
var/headquarters = "" // Location of the organization's HQ. Currently unused.
|
||||
var/motto = "" // A motto/jingle/whatever, if they have one. Currently unused.
|
||||
|
||||
var/list/ship_prefixes = list() //Some might have more than one! Like NanoTrasen. Value is the mission they perform, e.g. ("ABC" = "mission desc")
|
||||
var/list/ship_names = list( //Names of spaceships. This is a mostly generic list that all the other organizations inherit from if they don't have anything better.
|
||||
"Kestrel",
|
||||
"Beacon",
|
||||
"Signal",
|
||||
"Freedom",
|
||||
"Glory",
|
||||
"Axiom",
|
||||
"Eternal",
|
||||
"Icarus",
|
||||
"Harmony",
|
||||
"Light",
|
||||
"Discovery",
|
||||
"Endeavour",
|
||||
"Explorer",
|
||||
"Swift",
|
||||
"Dragonfly",
|
||||
"Ascendant",
|
||||
"Tenacious",
|
||||
"Pioneer",
|
||||
"Hawk",
|
||||
"Haste",
|
||||
"Radiant",
|
||||
"Luminous"
|
||||
)
|
||||
var/list/destination_names = list() //Names of static holdings that the organization's ships visit regularly.
|
||||
var/autogenerate_destination_names = TRUE
|
||||
|
||||
/datum/lore/organization/New()
|
||||
..()
|
||||
if(autogenerate_destination_names) // Lets pad out the destination names.
|
||||
var/i = rand(6, 10)
|
||||
var/list/star_names = list(
|
||||
"Sol", "Alpha Centauri", "Sirius", "Vega", "Regulus", "Vir", "Algol", "Aldebaran",
|
||||
"Delta Doradus", "Menkar", "Geminga", "Elnath", "Gienah", "Mu Leporis", "Nyx", "Tau Ceti",
|
||||
"Wazn", "Alphard", "Phact", "Altair")
|
||||
var/list/destination_types = list("dockyard", "station", "vessel", "waystation", "telecommunications satellite", "spaceport", "distress beacon", "anomaly", "colony", "outpost")
|
||||
while(i)
|
||||
destination_names.Add("a [pick(destination_types)] in [pick(star_names)]")
|
||||
i--
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// TSCs
|
||||
/datum/lore/organization/nanotrasen
|
||||
name = "NanoTrasen Incorporated"
|
||||
short_name = "NanoTrasen"
|
||||
desc = "" // Todo: Write this.
|
||||
history = "" // This too.
|
||||
work = "research giant"
|
||||
headquarters = "Luna"
|
||||
motto = ""
|
||||
|
||||
ship_prefixes = list("NSV" = "exploration", "NTV" = "hauling", "NDV" = "patrol", "NRV" = "emergency response")
|
||||
// Note that the current station being used will be pruned from this list upon being instantiated
|
||||
destination_names = list(
|
||||
"NSS Exodus in Nyx",
|
||||
"NCS Northern Star in Vir",
|
||||
"NCS Southern Cross in Vir",
|
||||
"NDV Icarus in Nyx",
|
||||
"NAS Vir Central Command",
|
||||
"a dockyard orbiting Sif",
|
||||
"an asteroid orbiting Kara",
|
||||
"an asteroid orbiting Rota",
|
||||
"Vir Interstellar Spaceport"
|
||||
)
|
||||
|
||||
/datum/lore/organization/nanotrasen/New()
|
||||
..()
|
||||
// Get rid of the current map from the list, so ships flying in don't say they're coming to the current map.
|
||||
var/string_to_test = "[using_map.station_name] in [using_map.starsys_name]"
|
||||
if(string_to_test in destination_names)
|
||||
destination_names.Remove(string_to_test)
|
||||
|
||||
|
||||
|
||||
/datum/lore/organization/hephaestus
|
||||
name = "Hephaestus Industries"
|
||||
short_name = "Hephaestus"
|
||||
desc = "Hephaestus Industries is the largest supplier of arms, ammunition, and small millitary vehicles in Sol space. \
|
||||
Hephaestus products have a reputation for reliability, and the corporation itself has a noted tendency to stay removed \
|
||||
from corporate politics. They enforce their neutrality with the help of a fairly large asset-protection contingent which \
|
||||
prevents any contracting polities from using their own materiel against them. SolGov itself is one of Hephastus’ largest \
|
||||
bulk contractors owing to the above factors."
|
||||
history = ""
|
||||
work = "arms manufacturer"
|
||||
headquarters = ""
|
||||
motto = ""
|
||||
|
||||
ship_prefixes = list("HTV" = "freight", "HTV" = "munitions resupply")
|
||||
destination_names = list(
|
||||
"a SolGov dockyard on Luna"
|
||||
)
|
||||
|
||||
/datum/lore/organization/vey_med
|
||||
name = "Vey Medical"
|
||||
short_name = "Vey Med"
|
||||
desc = "Vey-Med is one of the newer TSCs on the block and is notable for being largely owned and opperated by Skrell. \
|
||||
Despite the suspicion and prejudice leveled at them for their alien origin, Vey-Med has obtained market dominance in \
|
||||
the sale of medical equipment-- from surgical tools to large medical devices to the Oddyseus trauma response mecha \
|
||||
and everything in between. Their equipment tends to be top-of-the-line, most obviously shown by their incredibly \
|
||||
human-like FBP designs. Vey’s rise to stardom came from their introduction of ressurective cloning, although in \
|
||||
recent years they’ve been forced to diversify as their patents expired and NanoTrasen-made medications became \
|
||||
essential to modern cloning."
|
||||
history = ""
|
||||
work = "medical equipment supplier"
|
||||
headquarters = ""
|
||||
motto = ""
|
||||
|
||||
ship_prefixes = list("VTV" = "transportation", "VMV" = "medical resupply")
|
||||
destination_names = list()
|
||||
|
||||
/datum/lore/organization/zeng_hu
|
||||
name = "Zeng-Hu pharmaceuticals"
|
||||
short_name = "Zeng-Hu"
|
||||
desc = "Zeng-Hu is an old TSC, based in the Sol system. Until the discovery of Phoron, Zeng-Hu maintained a stranglehold \
|
||||
on the market for medications, and many household names are patentted by Zeng-Hu-- Bicaridyne, Dylovene, Tricordrizine, \
|
||||
and Dexalin all came from a Zeng-Hu medical laboratory. Zeng-Hu’s fortunes have been in decline as Nanotrasen’s near monopoly \
|
||||
on phoron research cuts into their R&D and Vey-Med’s superior medical equipment effectively decimated their own equipment \
|
||||
interests. The three-way rivalry between these companies for dominance in the medical field is well-known and a matter of \
|
||||
constant economic speculation."
|
||||
history = ""
|
||||
work = "pharmaceuticals company"
|
||||
headquarters = ""
|
||||
motto = ""
|
||||
|
||||
ship_prefixes = list("ZTV" = "transportation", "ZMV" = "medical resupply")
|
||||
destination_names = list()
|
||||
|
||||
/datum/lore/organization/ward_takahashi
|
||||
name = "Ward-Takahashi General Manufacturing Conglomerate"
|
||||
short_name = "Ward-Takahashi"
|
||||
desc = "Ward-Takahashi focuses on the sale of small consumer electronics, with its computers, communicators, \
|
||||
and even mid-class automobiles a fixture of many households. Less famously, Ward-Takahashi also supplies most \
|
||||
of the AI cores on which vital control systems are mounted, and it is this branch of their industry that has \
|
||||
led to their tertiary interest in the development and sale of high-grade AI systems. Ward-Takahashi’s economies \
|
||||
of scale frequently steal market share from Nanotrasen’s high-price products, leading to a bitter rivalry in the \
|
||||
consumer electronics market."
|
||||
history = ""
|
||||
work = "electronics manufacturer"
|
||||
headquarters = ""
|
||||
motto = ""
|
||||
|
||||
ship_prefixes = list("WTV" = "freight")
|
||||
destination_names = list()
|
||||
|
||||
/datum/lore/organization/bishop
|
||||
name = "Bishop Cybernetics"
|
||||
short_name = "Bishop"
|
||||
desc = "Bishop’s focus is on high-class, stylish cybernetics. A favorite among transhumanists (and a bête noire for \
|
||||
bioconservatives), Bishop manufactures not only prostheses but also brain augmentation, synthetic organ replacements, \
|
||||
and odds and ends like implanted wrist-watches. Their business model tends towards smaller, boutique operations, giving \
|
||||
it a reputation for high price and luxury, with Bishop cyberware often rivalling Vey-Med’s for cost. Bishop’s reputation \
|
||||
for catering towards the interests of human augmentation enthusiasts instead of positronics have earned it ire from the \
|
||||
Positronic Rights Group and puts it in ideological (but not economic) comptetition with Morpheus Cyberkinetics."
|
||||
history = ""
|
||||
work = "cybernetics and augmentation manufacturer"
|
||||
headquarters = ""
|
||||
motto = ""
|
||||
|
||||
ship_prefixes = list("BTV" = "transportation")
|
||||
destination_names = list()
|
||||
|
||||
/datum/lore/organization/morpheus
|
||||
name = "Morpheus Cyberkinetics"
|
||||
short_name = "Morpheus"
|
||||
desc = "The only large corporation run by positronic intelligences, Morpheus caters almost exclusively to their sensibilities \
|
||||
and needs. A product of the synthetic colony of Shelf, Morpheus eschews traditional advertising to keep their prices low and \
|
||||
relied on word of mouth among positronics to reach their current economic dominance. Morpheus in exchange lobbies heavily for \
|
||||
positronic rights, sponsors positronics through their Jans-Fhriede test, and tends to other positronic concerns to earn them \
|
||||
the good-will of the positronics, and the ire of those who wish to exploit them."
|
||||
history = ""
|
||||
work = "cybernetics manufacturer"
|
||||
headquarters = ""
|
||||
motto = ""
|
||||
|
||||
ship_prefixes = list("MTV" = "freight")
|
||||
// Culture names, because Anewbe told me so.
|
||||
ship_names = list(
|
||||
"Nervous Energy",
|
||||
"Prosthetic Conscience",
|
||||
"Revisionist",
|
||||
"Trade Surplus",
|
||||
"Flexible Demeanour",
|
||||
"Just Read The Instructions",
|
||||
"Limiting Factor",
|
||||
"Cargo Cult",
|
||||
"Gunboat Diplomat",
|
||||
"A Ship With A View",
|
||||
"Cantankerous",
|
||||
"I Thought He Was With You",
|
||||
"Never Talk To Strangers",
|
||||
"Sacrificial Victim",
|
||||
"Unwitting Accomplice",
|
||||
"Bad For Business",
|
||||
"Just Testing",
|
||||
"Size Isn't Everything",
|
||||
"Yawning Angel",
|
||||
"Liveware Problem",
|
||||
"Very Little Gravitas Indeed",
|
||||
"Zero Gravitas",
|
||||
"Gravitas Free Zone",
|
||||
"Absolutely No You-Know-What",
|
||||
"Existence Is Pain",
|
||||
"I'm Walking Here",
|
||||
"Screw Loose",
|
||||
"Of Course I Still Love You",
|
||||
"Limiting Factor",
|
||||
"So Much For Subtley",
|
||||
"Unfortunate Conflict Of Evidence",
|
||||
"Prime Mover",
|
||||
"It's One Of Ours",
|
||||
"Thank You And Goodnight",
|
||||
"Boo!",
|
||||
"Reasonable Excuse",
|
||||
"Honest Mistake",
|
||||
"Appeal To Reason",
|
||||
"My First Ship II",
|
||||
"Hidden Income",
|
||||
"Anything Legal Considered",
|
||||
"New Toy",
|
||||
"Me, I'm Always Counting",
|
||||
"Just Five More Minutes"
|
||||
|
||||
|
||||
)
|
||||
destination_names = list()
|
||||
|
||||
/datum/lore/organization/xion
|
||||
name = "Xion Manufacturing Group"
|
||||
short_name = "Xion"
|
||||
desc = "Xion, quietly, controls most of the market for industrial equipment. Their portfolio includes mining exosuits, \
|
||||
factory equipment, rugged positronic chassis, and other pieces of equipment vital to the function of the economy. Xion \
|
||||
keeps its control of the market by leasing, not selling, their equipment, and through infamous and bloody patent protection \
|
||||
lawsuits. Xion are noted to be a favorite contractor for SolGov engineers, owing to their low cost and rugged design."
|
||||
history = ""
|
||||
work = "industrial equipment manufacturer"
|
||||
headquarters = ""
|
||||
motto = ""
|
||||
|
||||
ship_prefixes = list("XTV" = "hauling")
|
||||
destination_names = list()
|
||||
|
||||
// Governments
|
||||
|
||||
/datum/lore/organization/sifgov
|
||||
name = "Sif Governmental Authority"
|
||||
short_name = "SifGov"
|
||||
desc = "SifGov is the sole governing administration for the Vir system, based in New Reykjavik, Sif. It is a representative \
|
||||
democratic government, and a fully recognized member of the Solar Confederate Government. Anyone operating inside of Vir must \
|
||||
comply with SifGov's legislation and regulations."
|
||||
history = "" // Todo like the rest of them
|
||||
work = "governing body of Sif"
|
||||
headquarters = "New Reykjavik, Sif"
|
||||
motto = ""
|
||||
autogenerate_destination_names = FALSE
|
||||
|
||||
ship_prefixes = list("SGA" = "hauling", "SGA" = "energy relay")
|
||||
destination_names = list(
|
||||
"New Reykjavik on Sif",
|
||||
"Radiance Energy Chain",
|
||||
"a dockyard orbiting Sif",
|
||||
"a telecommunications satellite",
|
||||
"Vir Interstellar Spaceport"
|
||||
)
|
||||
|
||||
/datum/lore/organization/solgov
|
||||
name = "Solar Confederate Government"
|
||||
short_name = "SolGov"
|
||||
desc = "SolGov is a decentralized confederation of human governmental entities based on Luna, Sol, which defines top-level law for their member states. \
|
||||
Member states receive various benefits such as defensive pacts, trade agreements, social support and funding, and being able to participate \
|
||||
in the Colonial Assembly. The majority, but not all human territories are members of SolGov. As such, SolGov is a major power and \
|
||||
defacto represents humanity on the galatic stage."
|
||||
history = "" // Todo
|
||||
work = "governing polity of humanity's Confederation"
|
||||
headquarters = "Luna"
|
||||
motto = "Nil Mortalibus Ardui Est" // Latin, because latin. Says 'Nothing is too steep for mortals'.
|
||||
autogenerate_destination_names = TRUE
|
||||
|
||||
ship_prefixes = list("SCG-T" = "transportation", "SCG-D" = "diplomatic", "SCG-F" = "freight")
|
||||
destination_names = list(
|
||||
"Venus",
|
||||
"Earth",
|
||||
"Luna",
|
||||
"Mars",
|
||||
"Titan"
|
||||
)// autogen will add a lot of other places as well.
|
||||
|
||||
/*
|
||||
// To be expanded upon later, once the military lore gets sorted out.
|
||||
|
||||
// Military
|
||||
|
||||
/datum/lore/organization/sif_guard
|
||||
name = "Sif Homeguard Forces" // Todo: Get better name from lorepeople.
|
||||
short_name = "SifGuard"
|
||||
desc = ""
|
||||
history = ""
|
||||
work = "Sif Governmental Authority's military"
|
||||
headquarters = "Sif" // Make this more specific later.
|
||||
motto = ""
|
||||
autogenerate_destination_names = FALSE // Kinda weird if SifGuard goes to Nyx.
|
||||
|
||||
ship_prefixes = list("SGSC" = "military", "SGSC" = "patrol", "SGSC" = "rescue", "SGSC" = "emergency response") // Todo: Replace prefix with better one.
|
||||
destination_names = list(
|
||||
"a classified location in SolGov territory",
|
||||
"Sif orbit",
|
||||
"the rings of Kara",
|
||||
"the rings of Rota",
|
||||
"Firnir orbit",
|
||||
"Tyr orbit",
|
||||
"Magni orbit",
|
||||
"a wreck in SifGov territory",
|
||||
"a military outpost",
|
||||
)
|
||||
*/
|
||||
@@ -126,6 +126,12 @@ var/list/_client_preferences_by_type
|
||||
enabled_description = "Show"
|
||||
disabled_description = "Hide"
|
||||
|
||||
/datum/client_preference/check_mention
|
||||
description ="Emphasize Name Mention"
|
||||
key = "CHAT_MENTION"
|
||||
enabled_description = "Emphasize"
|
||||
disabled_description = "Normal"
|
||||
|
||||
/datum/client_preference/show_progress_bar
|
||||
description ="Progress Bar"
|
||||
key = "SHOW_PROGRESS"
|
||||
|
||||
@@ -8,3 +8,8 @@
|
||||
/datum/gear/ears/headphones
|
||||
display_name = "headphones"
|
||||
path = /obj/item/clothing/ears/earmuffs/headphones
|
||||
|
||||
/datum/gear/ears/translator
|
||||
display_name = "universal translator, ear"
|
||||
path = /obj/item/device/universal_translator/ear
|
||||
cost = 5
|
||||
@@ -61,3 +61,8 @@
|
||||
cost = 2
|
||||
slot = "implant"
|
||||
var/implant_type = "EAL"
|
||||
|
||||
/datum/gear/utility/translator
|
||||
display_name = "universal translator"
|
||||
path = /obj/item/device/universal_translator
|
||||
cost = 5
|
||||
|
||||
@@ -199,10 +199,7 @@
|
||||
|
||||
/obj/item/clothing/gloves/emp_act(severity)
|
||||
if(cell)
|
||||
//why is this not part of the powercell code?
|
||||
cell.charge -= 1000 / severity
|
||||
if (cell.charge < 0)
|
||||
cell.charge = 0
|
||||
cell.emp_act(severity)
|
||||
..()
|
||||
|
||||
// Called just before an attack_hand(), in mob/UnarmedAttack()
|
||||
|
||||
@@ -705,16 +705,16 @@
|
||||
/obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza
|
||||
price_tag = 5
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/margheritaslice
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/margherita
|
||||
price_tag = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/meatpizzaslice
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/meatpizza
|
||||
price_tag = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/mushroompizzaslice
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/mushroompizza
|
||||
price_tag = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/vegetablepizzaslice
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/vegetablepizza
|
||||
price_tag = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/
|
||||
@@ -737,37 +737,37 @@
|
||||
/obj/item/weapon/reagent_containers/food/snacks/sliceable/meatbread
|
||||
price_tag = 5
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/meatbreadslice
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/meatbread
|
||||
price_tag = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/sliceable/xenomeatbread
|
||||
price_tag = 5
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/xenomeatbreadslice
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/xenomeatbread
|
||||
price_tag = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/sliceable/bananabread
|
||||
price_tag = 5
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/bananabreadslice
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/bananabread
|
||||
price_tag = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/sliceable/tofubread
|
||||
price_tag = 5
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/tofubreadslice
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/tofubread
|
||||
price_tag = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/sliceable/bread
|
||||
price_tag = 5
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/breadslice
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/bread
|
||||
price_tag = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/sliceable/creamcheesebread
|
||||
price_tag = 5
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/creamcheesebreadslice
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/creamcheesebread
|
||||
price_tag = 1
|
||||
|
||||
|
||||
@@ -845,67 +845,67 @@
|
||||
/obj/item/weapon/reagent_containers/food/snacks/sliceable/carrotcake
|
||||
price_tag = 5
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/carrotcakeslice
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/carrotcake
|
||||
price_tag = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/sliceable/braincake
|
||||
price_tag = 5
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/braincakeslice
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/braincake
|
||||
price_tag = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/sliceable/cheesecake
|
||||
price_tag = 5
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/cheesecakeslice
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/cheesecake
|
||||
price_tag = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/sliceable/plaincake
|
||||
price_tag = 5
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/plaincakeslice
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/plaincake
|
||||
price_tag = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/sliceable/orangecake
|
||||
price_tag = 5
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/orangecakeslice
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/orangecake
|
||||
price_tag = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/sliceable/limecake
|
||||
price_tag = 5
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/limecakeslice
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/limecake
|
||||
price_tag = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/sliceable/lemoncake
|
||||
price_tag = 5
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/lemoncakeslice
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/lemoncake
|
||||
price_tag = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/sliceable/chocolatecake
|
||||
price_tag = 5
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/chocolatecakeslice
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/chocolatecake
|
||||
price_tag = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/sliceable/birthdaycake
|
||||
price_tag = 5
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/birthdaycakeslice
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/birthdaycake
|
||||
price_tag = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/sliceable/applecake
|
||||
price_tag = 5
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/applecakeslice
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/applecake
|
||||
price_tag = 1
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/sliceable/pumpkinpie
|
||||
price_tag = 5
|
||||
|
||||
/obj/item/weapon/reagent_containers/food/snacks/pumpkinpieslice
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/pumpkinpie
|
||||
price_tag = 1
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// This event causes a gas leak of phoron, sleeping_agent, or carbon_dioxide in a random unoccupied area.
|
||||
// One wonders, where did the gas come from? Who knows! Its SPACE! But if you want something a touch
|
||||
// more "explainable" then check out the canister_leak event instead.
|
||||
//
|
||||
|
||||
/datum/event/atmos_leak
|
||||
startWhen = 5 // Nobody will actually be in the room, but still give a bit of warning.
|
||||
var/area/target_area // Chosen target area
|
||||
var/area/target_turf // Chosen target turf in target_area
|
||||
var/gas_type // Chosen gas to release
|
||||
// Exclude these types and sub-types from targeting eligibilty
|
||||
var/list/area/excluded = list(
|
||||
/area/shuttle,
|
||||
/area/crew_quarters,
|
||||
/area/holodeck,
|
||||
/area/engineering/engine_room
|
||||
)
|
||||
|
||||
// Decide which area will be targeted!
|
||||
/datum/event/atmos_leak/setup()
|
||||
var/gas_choices = list("carbon_dioxide", "sleeping_agent") // Annoying
|
||||
if(severity >= EVENT_LEVEL_MODERATE)
|
||||
gas_choices += "phoron" // Dangerous
|
||||
if(severity >= EVENT_LEVEL_MAJOR)
|
||||
gas_choices += "volatile_fuel" // Dangerous and no default atmos setup!
|
||||
gas_type = pick(gas_choices)
|
||||
|
||||
// Assemble areas that all exists (See DM reference if you are confused about loop labels)
|
||||
var/list/area/grand_list_of_areas = list()
|
||||
looping_station_areas:
|
||||
for(var/parentpath in global.the_station_areas)
|
||||
// Check its not excluded
|
||||
for(var/excluded_path in excluded)
|
||||
if(ispath(parentpath, excluded_path))
|
||||
continue looping_station_areas
|
||||
// Otherwise add it and all subtypes that exist on the map to our grand list
|
||||
for(var/areapath in typesof(parentpath))
|
||||
var/area/A = locate(areapath) // Check if it actually exists
|
||||
if(istype(A) && A.z in using_map.player_levels)
|
||||
grand_list_of_areas += A
|
||||
|
||||
// Okay, now lets try and pick a target! Lets try 10 times, otherwise give up
|
||||
for(var/i in 1 to 10)
|
||||
var/area/A = pick(grand_list_of_areas)
|
||||
if(is_area_occupied(A))
|
||||
log_debug("atmos_leak event: Rejected [A] because it is occupied.")
|
||||
continue
|
||||
// A good area, great! Lets try and pick a turf
|
||||
var/list/turfs = list()
|
||||
for(var/turf/simulated/floor/F in A)
|
||||
if(turf_clear(F))
|
||||
turfs += F
|
||||
if(turfs.len == 0)
|
||||
log_debug("atmos_leak event: Rejected [A] because it has no clear turfs.")
|
||||
continue
|
||||
target_area = A
|
||||
target_turf = pick(turfs)
|
||||
|
||||
// If we can't find a good target, give up
|
||||
if(!target_area)
|
||||
log_debug("atmos_leak event: Giving up after too many failures to pick target area")
|
||||
kill()
|
||||
return
|
||||
|
||||
/** Checks if any living humans are in a given area! */
|
||||
/datum/event/atmos_leak/proc/is_area_occupied(var/area/myarea)
|
||||
// Testing suggests looping over human_mob_list is quicker than looping over area contents
|
||||
for(var/mob/living/carbon/human/H in human_mob_list)
|
||||
if(H.stat >= DEAD) //Conditions for exclusion here, like if disconnected people start blocking it.
|
||||
continue
|
||||
var/area/A = get_area(H)
|
||||
if(A == myarea) //The loc of a turf is the area it is in.
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/event/atmos_leak/announce()
|
||||
command_announcement.Announce("Warning, hazardous [gas_data.name[gas_type]] gas leak detected in \the [target_area], evacuate the area and contain the damage!", "Hazard Alert")
|
||||
|
||||
/datum/event/atmos_leak/start()
|
||||
// Okay, time to actually put the gas in the room!
|
||||
// TODO - Would be nice to break a waste pipe perhaps?
|
||||
// TODO - Maybe having it released from a single point and thus causing airflow to blow stuff around
|
||||
|
||||
// Fow now just add a bunch of it to the air
|
||||
var/datum/gas_mixture/air_contents = new
|
||||
air_contents.temperature = T20C + ((severity - 1) * rand(-50, 50))
|
||||
air_contents.gas[gas_type] = 10 * MOLES_CELLSTANDARD
|
||||
target_turf.assume_air(air_contents)
|
||||
playsound(target_turf, 'sound/effects/smoke.ogg', 50, 1)
|
||||
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// This event chooses a random canister on player levels and breaks it, releasing its contents!
|
||||
// On severity EVENT_LEVEL_MUNDANE or below it checks to make sure nobody is in the area, otherwise... good luck.
|
||||
//
|
||||
|
||||
/datum/event/canister_leak/start()
|
||||
// List of all non-destroyed canisters on station levels
|
||||
var/list/all_canisters = list()
|
||||
for(var/obj/machinery/portable_atmospherics/canister/C in machines)
|
||||
if(!C.destroyed && (C.z in using_map.station_levels) && C.air_contents.total_moles >= MOLES_CELLSTANDARD)
|
||||
all_canisters += C
|
||||
|
||||
for(var/i in 1 to 10)
|
||||
var/obj/machinery/portable_atmospherics/canister/C = pick(all_canisters)
|
||||
if(severity <= EVENT_LEVEL_MUNDANE && area_is_occupied(get_area(C)))
|
||||
log_debug("canister_leak event: Rejecting canister [C] ([C.x],[C.y],[C.z]) because area is occupied")
|
||||
continue
|
||||
// Okay lets break it
|
||||
break_canister(C)
|
||||
return
|
||||
|
||||
// If we got to here we failed to find it
|
||||
log_debug("canister_leak event: Giving up after too many failures to pick target canister")
|
||||
kill()
|
||||
return
|
||||
|
||||
/datum/event/canister_leak/proc/break_canister(var/obj/machinery/portable_atmospherics/canister/C)
|
||||
log_debug("canister_leak event: Canister [C] ([C.x],[C.y],[C.z]) destroyed.")
|
||||
C.health = 0
|
||||
C.healthcheck()
|
||||
@@ -86,6 +86,12 @@
|
||||
"admin","ponies","heresy","meow","Pun Pun","monkey","Ian","moron","pizza","message","spam",\
|
||||
"director", "Hello", "Hi!"," ","nuke","crate","dwarf","xeno")
|
||||
|
||||
/datum/event/ionstorm/tick()
|
||||
if(botEmagChance)
|
||||
for(var/mob/living/bot/bot in world)
|
||||
if(prob(botEmagChance))
|
||||
bot.emag_act(1)
|
||||
|
||||
/datum/event/ionstorm/end()
|
||||
spawn(rand(5000,8000))
|
||||
if(prob(50))
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
else
|
||||
num = rand(2,6)
|
||||
for(var/i=0, i<num, i++)
|
||||
var/mob/living/simple_animal/hostile/retaliate/malf_drone/D = new(get_turf(pick(possible_spawns)))
|
||||
var/mob/living/simple_animal/hostile/malf_drone/D = new(get_turf(pick(possible_spawns)))
|
||||
drones_list.Add(D)
|
||||
if(prob(25))
|
||||
D.disabled = rand(15, 60)
|
||||
@@ -42,7 +42,7 @@
|
||||
|
||||
/datum/event/rogue_drone/end()
|
||||
var/num_recovered = 0
|
||||
for(var/mob/living/simple_animal/hostile/retaliate/malf_drone/D in drones_list)
|
||||
for(var/mob/living/simple_animal/hostile/malf_drone/D in drones_list)
|
||||
var/datum/effect/effect/system/spark_spread/sparks = new /datum/effect/effect/system/spark_spread()
|
||||
sparks.set_up(3, 0, D.loc)
|
||||
sparks.start()
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
/client/proc/recipe_dump()
|
||||
set name = "Generate Recipe Dump"
|
||||
set category = "Server"
|
||||
set desc = "Dumps food and drink recipe info and images for wiki or other use."
|
||||
|
||||
if(!holder)
|
||||
return
|
||||
|
||||
//////////////////////// DRINK
|
||||
var/list/drink_recipes = list()
|
||||
for(var/path in typesof(/datum/chemical_reaction/drinks) - /datum/chemical_reaction/drinks)
|
||||
var/datum/chemical_reaction/drinks/CR = new path()
|
||||
drink_recipes[path] = list("Result" = CR.name,
|
||||
"ResAmt" = CR.result_amount,
|
||||
"Reagents" = CR.required_reagents)
|
||||
qdel(CR)
|
||||
|
||||
//////////////////////// FOOD
|
||||
var/list/food_recipes = typesof(/datum/recipe) - /datum/recipe
|
||||
//Build a useful list
|
||||
for(var/Rp in food_recipes)
|
||||
//Lists don't work with datum-stealing no-instance initial() so we have to.
|
||||
var/datum/recipe/R = new Rp()
|
||||
var/obj/res = new R.result()
|
||||
|
||||
var/icon/result_icon = icon(res.icon,res.icon_state)
|
||||
result_icon.Scale(64,64)
|
||||
|
||||
food_recipes[Rp] = list(
|
||||
"Result" = "[res.name]",
|
||||
"ResAmt" = "1",
|
||||
"Reagents" = R.reagents,
|
||||
"Fruit" = R.fruit,
|
||||
"Ingredients" = R.items,
|
||||
"Image" = result_icon
|
||||
)
|
||||
|
||||
qdel(res)
|
||||
qdel(R)
|
||||
|
||||
//////////////////////// FOOD+ (basically condiments, tofu, cheese, soysauce, etc)
|
||||
for(var/path in typesof(/datum/chemical_reaction/food) - /datum/chemical_reaction/food)
|
||||
var/datum/chemical_reaction/food/CR = new path()
|
||||
food_recipes[path] = list("Result" = CR.name,
|
||||
"ResAmt" = CR.result_amount,
|
||||
"Reagents" = CR.required_reagents,
|
||||
"Fruit" = list(),
|
||||
"Ingredients" = list(),
|
||||
"Image" = null)
|
||||
qdel(CR)
|
||||
|
||||
//////////////////////// PROCESSING
|
||||
//Items needs further processing into human-readability.
|
||||
for(var/Rp in food_recipes)
|
||||
var/working_ing_list = list()
|
||||
for(var/I in food_recipes[Rp]["Ingredients"])
|
||||
var/atom/ing = new I()
|
||||
|
||||
//So now we add something like "Bread" = 3
|
||||
if(ing.name in working_ing_list)
|
||||
var/sofar = working_ing_list[ing.name]
|
||||
working_ing_list[ing.name] = sofar+1
|
||||
else
|
||||
working_ing_list[ing.name] = 1
|
||||
|
||||
food_recipes[Rp]["Ingredients"] = working_ing_list
|
||||
|
||||
//Reagents can be resolved to nicer names as well
|
||||
for(var/Rp in food_recipes)
|
||||
for(var/rid in food_recipes[Rp]["Reagents"])
|
||||
var/datum/reagent/Rd = chemical_reagents_list[rid]
|
||||
var/R_name = Rd.name
|
||||
var/amt = food_recipes[Rp]["Reagents"][rid]
|
||||
food_recipes[Rp]["Reagents"] -= rid
|
||||
food_recipes[Rp]["Reagents"][R_name] = amt
|
||||
for(var/Rp in drink_recipes)
|
||||
for(var/rid in drink_recipes[Rp]["Reagents"])
|
||||
var/datum/reagent/Rd = chemical_reagents_list[rid]
|
||||
var/R_name = Rd.name
|
||||
var/amt = drink_recipes[Rp]["Reagents"][rid]
|
||||
drink_recipes[Rp]["Reagents"] -= rid
|
||||
drink_recipes[Rp]["Reagents"][R_name] = amt
|
||||
|
||||
//////////////////////// SORTING
|
||||
var/list/foods_to_paths = list()
|
||||
var/list/drinks_to_paths = list()
|
||||
|
||||
for(var/Rp in food_recipes)
|
||||
foods_to_paths["[food_recipes[Rp]["Result"]] [Rp]"] = Rp //Append recipe datum path to keep uniqueness
|
||||
for(var/Rp in drink_recipes)
|
||||
drinks_to_paths["[drink_recipes[Rp]["Result"]] [Rp]"] = Rp
|
||||
|
||||
foods_to_paths = sortAssoc(foods_to_paths)
|
||||
drinks_to_paths = sortAssoc(drinks_to_paths)
|
||||
|
||||
var/list/foods_newly_sorted = list()
|
||||
var/list/drinks_newly_sorted = list()
|
||||
|
||||
for(var/Rr in foods_to_paths)
|
||||
var/Rp = foods_to_paths[Rr]
|
||||
foods_newly_sorted[Rp] = food_recipes[Rp]
|
||||
for(var/Rr in drinks_to_paths)
|
||||
var/Rp = drinks_to_paths[Rr]
|
||||
drinks_newly_sorted[Rp] = drink_recipes[Rp]
|
||||
|
||||
food_recipes = foods_newly_sorted
|
||||
drink_recipes = drinks_newly_sorted
|
||||
|
||||
//////////////////////// OUTPUT
|
||||
//Food Output
|
||||
var/html = "<head>\
|
||||
<meta charset='utf-8'>\
|
||||
<meta http-equiv='X-UA-Compatible' content='IE=edge'>\
|
||||
<meta http-equiv='content-language' content='en-us' />\
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1'>\
|
||||
<title>Food Recipes</title>\
|
||||
<link rel='stylesheet' href='food.css' />\
|
||||
</head>"
|
||||
|
||||
html += "<html><body><h3>Food Recipes (as of [time2text(world.realtime,"MMM DD, YYYY")])</h3><br>"
|
||||
html += "<table class='recipes'>"
|
||||
html += "<tr><th>Icon</th><th>Name</th><th>Ingredients</th></tr>"
|
||||
for(var/Rp in food_recipes)
|
||||
//Open this row
|
||||
html += "<tr>"
|
||||
|
||||
//Image
|
||||
var/icon/icon_to_give = food_recipes[Rp]["Image"]
|
||||
if(icon_to_give)
|
||||
var/image_path = "recipe-[ckey(food_recipes[Rp]["Result"])].png"
|
||||
html += "<td><img src='imgrecipes/[image_path]' /></td>"
|
||||
src << browse(icon_to_give, "window=picture;file=[image_path];display=0")
|
||||
else
|
||||
html += "<td>No<br>Image</td>"
|
||||
|
||||
//Name
|
||||
html += "<td><b>[food_recipes[Rp]["Result"]]</b></td>"
|
||||
|
||||
//Ingredients
|
||||
html += "<td><ul>"
|
||||
var/count //For those commas. Not sure of a great other way to do it.
|
||||
//For each large ingredient
|
||||
var/pretty_ing = ""
|
||||
count = 0
|
||||
for(var/ing in food_recipes[Rp]["Ingredients"])
|
||||
pretty_ing += "[count == 0 ? "" : ", "][food_recipes[Rp]["Ingredients"][ing]]x [ing]"
|
||||
count++
|
||||
if(pretty_ing != "")
|
||||
html += "<li><b>Ingredients:</b> [pretty_ing]</li>"
|
||||
|
||||
//For each fruit
|
||||
var/pretty_fru = ""
|
||||
count = 0
|
||||
for(var/fru in food_recipes[Rp]["Fruit"])
|
||||
pretty_fru += "[count == 0 ? "" : ", "][food_recipes[Rp]["Fruit"][fru]]x [fru]"
|
||||
count++
|
||||
if(pretty_fru != "")
|
||||
html += "<li><b>Fruit:</b> [pretty_fru]</li>"
|
||||
|
||||
//For each reagent
|
||||
var/pretty_rea = ""
|
||||
count = 0
|
||||
for(var/rea in food_recipes[Rp]["Reagents"])
|
||||
pretty_rea += "[count == 0 ? "" : ", "][food_recipes[Rp]["Reagents"][rea]]u [rea]"
|
||||
count++
|
||||
if(pretty_rea != "")
|
||||
html += "<li><b>Mix in:</b> [pretty_rea]</li>"
|
||||
|
||||
//Close ingredients
|
||||
html += "</ul></td>"
|
||||
//Close this row
|
||||
html += "</tr>"
|
||||
|
||||
html += "</table></body></html>"
|
||||
src << browse(html, "window=recipes;file=recipes_food.html;display=0")
|
||||
|
||||
//Drink Output
|
||||
html = "<head>\
|
||||
<meta charset='utf-8'>\
|
||||
<meta http-equiv='X-UA-Compatible' content='IE=edge'>\
|
||||
<meta http-equiv='content-language' content='en-us' />\
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1'>\
|
||||
<title>Drink Recipes</title>\
|
||||
<link rel='stylesheet' href='drinks.css' />\
|
||||
</head>"
|
||||
|
||||
html += "<html><body><h3>Drink Recipes (as of [time2text(world.realtime,"MMM DD, YYYY")])</h3><br>"
|
||||
html += "<table class='recipes'>"
|
||||
html += "<tr><th>Name</th><th>Ingredients</th></tr>"
|
||||
for(var/Rp in drink_recipes)
|
||||
//Open this row
|
||||
html += "<tr>"
|
||||
|
||||
//Name
|
||||
html += "<td><b>[drink_recipes[Rp]["Result"]]</b></td>"
|
||||
|
||||
html += "<td>"
|
||||
//For each reagent
|
||||
var/pretty_rea = ""
|
||||
var/count = 0
|
||||
for(var/rea in drink_recipes[Rp]["Reagents"])
|
||||
pretty_rea += "[count == 0 ? "" : ", "][drink_recipes[Rp]["Reagents"][rea]]u [rea]"
|
||||
count++
|
||||
if(pretty_rea != "")
|
||||
html += "<li><b>Mix together:</b> [pretty_rea]</li>"
|
||||
|
||||
html += "<li>Makes [drink_recipes[Rp]["ResAmt"]]u</li>"
|
||||
|
||||
//Close reagents
|
||||
html += "</ul></td>"
|
||||
//Close this row
|
||||
html += "</tr>"
|
||||
|
||||
html += "</table></body></html>"
|
||||
src << browse(html, "window=recipes;file=recipes_drinks.html;display=0")
|
||||
|
||||
src << "<span class='notice'>In your byond cache, recipe-xxx.png files and recipes_drinks.html and recipes_food.html now exist. Place recipe-xxx.png files in a subfolder named 'imgrecipes' wherever you put them. The file will take a food.css or drinks.css file if in the same path.</span>"
|
||||
@@ -621,8 +621,8 @@ I said no!
|
||||
/datum/recipe/sandwich
|
||||
items = list(
|
||||
/obj/item/weapon/reagent_containers/food/snacks/meatsteak,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/breadslice,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/breadslice,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/bread,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/bread,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/cheesewedge,
|
||||
)
|
||||
result = /obj/item/weapon/reagent_containers/food/snacks/sandwich
|
||||
@@ -635,8 +635,8 @@ I said no!
|
||||
|
||||
/datum/recipe/grilledcheese
|
||||
items = list(
|
||||
/obj/item/weapon/reagent_containers/food/snacks/breadslice,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/breadslice,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/bread,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/bread,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/cheesewedge,
|
||||
)
|
||||
result = /obj/item/weapon/reagent_containers/food/snacks/grilledcheese
|
||||
@@ -663,14 +663,14 @@ I said no!
|
||||
/datum/recipe/slimetoast
|
||||
reagents = list("slimejelly" = 5)
|
||||
items = list(
|
||||
/obj/item/weapon/reagent_containers/food/snacks/breadslice,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/bread,
|
||||
)
|
||||
result = /obj/item/weapon/reagent_containers/food/snacks/jelliedtoast/slime
|
||||
|
||||
/datum/recipe/jelliedtoast
|
||||
reagents = list("cherryjelly" = 5)
|
||||
items = list(
|
||||
/obj/item/weapon/reagent_containers/food/snacks/breadslice,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/bread,
|
||||
)
|
||||
result = /obj/item/weapon/reagent_containers/food/snacks/jelliedtoast/cherry
|
||||
|
||||
@@ -783,24 +783,24 @@ I said no!
|
||||
/datum/recipe/twobread
|
||||
reagents = list("wine" = 5)
|
||||
items = list(
|
||||
/obj/item/weapon/reagent_containers/food/snacks/breadslice,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/breadslice,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/bread,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/bread,
|
||||
)
|
||||
result = /obj/item/weapon/reagent_containers/food/snacks/twobread
|
||||
|
||||
/datum/recipe/slimesandwich
|
||||
reagents = list("slimejelly" = 5)
|
||||
items = list(
|
||||
/obj/item/weapon/reagent_containers/food/snacks/breadslice,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/breadslice,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/bread,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/bread,
|
||||
)
|
||||
result = /obj/item/weapon/reagent_containers/food/snacks/jellysandwich/slime
|
||||
|
||||
/datum/recipe/cherrysandwich
|
||||
reagents = list("cherryjelly" = 5)
|
||||
items = list(
|
||||
/obj/item/weapon/reagent_containers/food/snacks/breadslice,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/breadslice,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/bread,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/slice/bread,
|
||||
)
|
||||
result = /obj/item/weapon/reagent_containers/food/snacks/jellysandwich/cherry
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// This event chooses a random canister on player levels and breaks it, releasing its contents!
|
||||
//
|
||||
|
||||
/datum/gm_action/canister_leak
|
||||
name = "Canister Leak"
|
||||
departments = list(ROLE_ENGINEERING)
|
||||
chaotic = 20
|
||||
|
||||
/datum/gm_action/canister_leak/get_weight()
|
||||
return metric.count_people_in_department(ROLE_ENGINEERING) * 30
|
||||
|
||||
/datum/gm_action/canister_leak/start()
|
||||
..()
|
||||
// List of all non-destroyed canisters on station levels
|
||||
var/list/all_canisters = list()
|
||||
for(var/obj/machinery/portable_atmospherics/canister/C in machines)
|
||||
if(!C.destroyed && (C.z in using_map.station_levels) && C.air_contents.total_moles >= MOLES_CELLSTANDARD)
|
||||
all_canisters += C
|
||||
var/obj/machinery/portable_atmospherics/canister/C = pick(all_canisters)
|
||||
log_debug("canister_leak event: Canister [C] ([C.x],[C.y],[C.z]) destroyed.")
|
||||
C.health = 0
|
||||
C.healthcheck()
|
||||
return
|
||||
@@ -184,7 +184,7 @@
|
||||
display_name = "killer tomato plant"
|
||||
mutants = null
|
||||
can_self_harvest = 1
|
||||
has_mob_product = /mob/living/simple_animal/tomato
|
||||
has_mob_product = /mob/living/simple_animal/hostile/tomato
|
||||
|
||||
/datum/seed/tomato/killer/New()
|
||||
..()
|
||||
|
||||
@@ -71,6 +71,8 @@
|
||||
new/datum/stack_recipe("airtight hatch assembly", /obj/structure/door_assembly/door_assembly_hatch, 4, time = 50, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("maintenance hatch assembly", /obj/structure/door_assembly/door_assembly_mhatch, 4, time = 50, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("high security airlock assembly", /obj/structure/door_assembly/door_assembly_highsecurity, 4, time = 50, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("voidcraft airlock assembly horizontal", /obj/structure/door_assembly/door_assembly_voidcraft, 4, time = 50, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("voidcraft airlock assembly vertical", /obj/structure/door_assembly/door_assembly_voidcraft/vertical, 4, time = 50, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("emergency shutter", /obj/structure/firedoor_assembly, 4, time = 50, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("multi-tile airlock assembly", /obj/structure/door_assembly/multi_tile, 4, time = 50, one_per_turf = 1, on_floor = 1), \
|
||||
))
|
||||
|
||||
@@ -597,7 +597,7 @@ var/list/name_to_material
|
||||
stack_type = /obj/item/stack/material/wood
|
||||
icon_colour = "#824B28"
|
||||
integrity = 50
|
||||
icon_base = "solid"
|
||||
icon_base = "wood"
|
||||
explosion_resistance = 2
|
||||
shard_type = SHARD_SPLINTER
|
||||
shard_can_repair = 0 // you can't weld splinters back into planks
|
||||
@@ -618,6 +618,12 @@ var/list/name_to_material
|
||||
stack_type = null
|
||||
shard_type = SHARD_NONE
|
||||
|
||||
/material/wood/sif
|
||||
name = "alien wood"
|
||||
// stack_type = /obj/item/stack/material/wood/sif
|
||||
icon_colour = "#0099cc" // Cyan-ish
|
||||
stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2) // Alien wood would presumably be more interesting to the analyzer.
|
||||
|
||||
/material/cardboard
|
||||
name = "cardboard"
|
||||
stack_type = /obj/item/stack/material/cardboard
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
if (message)
|
||||
log_emote("[name]/[key] : [message]")
|
||||
|
||||
message = say_emphasis(message)
|
||||
|
||||
// Hearing gasp and such every five seconds is not good emotes were not global for a reason.
|
||||
// Maybe some people are okay with that.
|
||||
|
||||
@@ -63,6 +65,8 @@
|
||||
else
|
||||
input = message
|
||||
|
||||
input = say_emphasis(input)
|
||||
|
||||
if(input)
|
||||
log_emote("Ghost/[src.key] : [input]")
|
||||
if(!invisibility) //If the ghost is made visible by admins or cult. And to see if the ghost has toggled its own visibility, as well. -Mech
|
||||
|
||||
@@ -32,14 +32,10 @@
|
||||
|
||||
if(!(language && (language.flags & INNATE))) // skip understanding checks for INNATE languages
|
||||
if(!say_understands(speaker,language))
|
||||
if(istype(speaker,/mob/living/simple_animal))
|
||||
var/mob/living/simple_animal/S = speaker
|
||||
message = pick(S.speak)
|
||||
if(language)
|
||||
message = language.scramble(message)
|
||||
else
|
||||
if(language)
|
||||
message = language.scramble(message)
|
||||
else
|
||||
message = stars(message)
|
||||
message = stars(message)
|
||||
|
||||
var/speaker_name = speaker.name
|
||||
if(istype(speaker, /mob/living/carbon/human))
|
||||
@@ -49,6 +45,8 @@
|
||||
if(italics)
|
||||
message = "<i>[message]</i>"
|
||||
|
||||
message = say_emphasis(message)
|
||||
|
||||
var/track = null
|
||||
if(istype(src, /mob/observer/dead))
|
||||
if(italics && is_preference_enabled(/datum/client_preference/ghost_radio))
|
||||
@@ -66,20 +64,73 @@
|
||||
else
|
||||
src << "<span class='name'>[speaker_name]</span>[alt_name] talks but you cannot hear."
|
||||
else
|
||||
var/message_to_send = null
|
||||
if(language)
|
||||
on_hear_say("<span class='game say'><span class='name'>[speaker_name]</span>[alt_name] [track][language.format_message(message, verb)]</span>")
|
||||
message_to_send = "<span class='game say'><span class='name'>[speaker_name]</span>[alt_name] [track][language.format_message(message, verb)]</span>"
|
||||
else
|
||||
on_hear_say("<span class='game say'><span class='name'>[speaker_name]</span>[alt_name] [track][verb], <span class='message'><span class='body'>\"[message]\"</span></span></span>")
|
||||
message_to_send = "<span class='game say'><span class='name'>[speaker_name]</span>[alt_name] [track][verb], <span class='message'><span class='body'>\"[message]\"</span></span></span>"
|
||||
if(check_mentioned(message) && is_preference_enabled(/datum/client_preference/check_mention))
|
||||
message_to_send = "<font size='3'><b>[message_to_send]</b></font>"
|
||||
|
||||
on_hear_say(message_to_send)
|
||||
|
||||
if (speech_sound && (get_dist(speaker, src) <= world.view && src.z == speaker.z))
|
||||
var/turf/source = speaker? get_turf(speaker) : get_turf(src)
|
||||
src.playsound_local(source, speech_sound, sound_vol, 1)
|
||||
|
||||
/mob/proc/on_hear_say(var/message)
|
||||
src << message
|
||||
to_chat(src, message)
|
||||
|
||||
/mob/living/silicon/on_hear_say(var/message)
|
||||
var/time = say_timestamp()
|
||||
src << "[time] [message]"
|
||||
to_chat(src, "[time] [message]")
|
||||
|
||||
// Checks if the mob's own name is included inside message. Handles both first and last names.
|
||||
/mob/proc/check_mentioned(var/message)
|
||||
var/list/valid_names = splittext(real_name, " ") // Should output list("John", "Doe") as an example.
|
||||
valid_names += special_mentions()
|
||||
for(var/name in valid_names)
|
||||
if(findtext(message, regex("\\b[name]\\b", "i"))) // This is to stop 'ai' from triggering if someone says 'wait'.
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
// Override this if you want something besides the mob's name to count for being mentioned in check_mentioned().
|
||||
/mob/proc/special_mentions()
|
||||
return list()
|
||||
|
||||
/mob/living/silicon/ai/special_mentions()
|
||||
return list("AI") // AI door!
|
||||
|
||||
// Converts specific characters, like *, /, and _ to formatted output.
|
||||
/mob/proc/say_emphasis(var/message)
|
||||
message = encode_html_emphasis(message, "/", "i")
|
||||
message = encode_html_emphasis(message, "+", "b")
|
||||
message = encode_html_emphasis(message, "_", "u")
|
||||
return message
|
||||
|
||||
// Replaces a character inside message with html tags. Note that html var must not include brackets.
|
||||
// Will not create an open html tag if it would not have a closing one.
|
||||
/proc/encode_html_emphasis(var/message, var/char, var/html)
|
||||
var/i = 20 // Infinite loop safety.
|
||||
var/pattern = "(?<!<)\\" + char
|
||||
var/regex/re = regex(pattern,"i") // This matches results which do not have a < next to them, to avoid stripping slashes from closing html tags.
|
||||
var/first = re.Find(message) // Find first occurance.
|
||||
var/second = re.Find(message, first + 1) // Then the second.
|
||||
while(first && second && i)
|
||||
// Calculate how far foward the second char is, as the first replacetext() will displace it.
|
||||
var/length_increase = length("<[html]>") - 1
|
||||
|
||||
// Now replace both.
|
||||
message = replacetext(message, char, "<[html]>", first, first + 1)
|
||||
message = replacetext(message, char, "</[html]>", second + length_increase, second + length_increase + 1)
|
||||
|
||||
// Check again to see if we need to keep going.
|
||||
first = re.Find(message)
|
||||
second = re.Find(message, first + 1)
|
||||
i--
|
||||
if(!i)
|
||||
CRASH("Possible infinite loop occured in encode_html_emphasis().")
|
||||
return message
|
||||
|
||||
/mob/proc/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0, var/vname ="")
|
||||
|
||||
@@ -182,11 +233,15 @@
|
||||
speaker_name = "[speaker.real_name] ([speaker_name])"
|
||||
track = "[speaker_name] ([ghost_follow_link(speaker, src)])"
|
||||
|
||||
message = say_emphasis(message)
|
||||
|
||||
var/formatted
|
||||
if(language)
|
||||
formatted = "[language.format_message_radio(message, verb)][part_c]"
|
||||
else
|
||||
formatted = "[verb], <span class=\"body\">\"[message]\"</span>[part_c]"
|
||||
|
||||
|
||||
if((sdisabilities & DEAF) || ear_deaf)
|
||||
if(prob(20))
|
||||
src << "<span class='warning'>You feel your headset vibrate but can hear nothing from it!</span>"
|
||||
@@ -197,18 +252,30 @@
|
||||
return "<span class='say_quote'>\[[stationtime2text()]\]</span>"
|
||||
|
||||
/mob/proc/on_hear_radio(part_a, speaker_name, track, part_b, formatted)
|
||||
src << "[part_a][speaker_name][part_b][formatted]"
|
||||
var/final_message = "[part_a][speaker_name][part_b][formatted]"
|
||||
if(check_mentioned(formatted) && is_preference_enabled(/datum/client_preference/check_mention))
|
||||
final_message = "<font size='3'><b>[final_message]</b></font>"
|
||||
to_chat(src, final_message)
|
||||
|
||||
/mob/observer/dead/on_hear_radio(part_a, speaker_name, track, part_b, formatted)
|
||||
src << "[part_a][track][part_b][formatted]"
|
||||
var/final_message = "[part_a][track][part_b][formatted]"
|
||||
if(check_mentioned(formatted) && is_preference_enabled(/datum/client_preference/check_mention))
|
||||
final_message = "<font size='3'><b>[final_message]</b></font>"
|
||||
to_chat(src, final_message)
|
||||
|
||||
/mob/living/silicon/on_hear_radio(part_a, speaker_name, track, part_b, formatted)
|
||||
var/time = say_timestamp()
|
||||
src << "[time][part_a][speaker_name][part_b][formatted]"
|
||||
var/final_message = "[part_a][speaker_name][part_b][formatted]"
|
||||
if(check_mentioned(formatted) && is_preference_enabled(/datum/client_preference/check_mention))
|
||||
final_message = "[time]<font size='3'><b>[final_message]</b></font>"
|
||||
to_chat(src, final_message)
|
||||
|
||||
/mob/living/silicon/ai/on_hear_radio(part_a, speaker_name, track, part_b, formatted)
|
||||
var/time = say_timestamp()
|
||||
src << "[time][part_a][track][part_b][formatted]"
|
||||
var/final_message = "[part_a][track][part_b][formatted]"
|
||||
if(check_mentioned(formatted) && is_preference_enabled(/datum/client_preference/check_mention))
|
||||
final_message = "[time]<font size='3'><b>[final_message]</b></font>"
|
||||
to_chat(src, final_message)
|
||||
|
||||
/mob/proc/hear_signlang(var/message, var/verb = "gestures", var/datum/language/language, var/mob/speaker = null)
|
||||
if(!client)
|
||||
|
||||
@@ -17,15 +17,19 @@
|
||||
if (!message)
|
||||
return
|
||||
|
||||
message = speaker.say_emphasis(message)
|
||||
|
||||
var/message_start = "<i><span class='game say'>[name], <span class='name'>[speaker.name]</span>"
|
||||
var/message_body = "<span class='message'>[speaker.say_quote(message)], \"[message]\"</span></span></i>"
|
||||
|
||||
for (var/mob/M in dead_mob_list)
|
||||
if(!istype(M,/mob/new_player) && !istype(M,/mob/living/carbon/brain)) //No meta-evesdropping
|
||||
M.show_message("[message_start] ([ghost_follow_link(speaker, M)]) [message_body]", 2)
|
||||
var/message_to_send = "[message_start] ([ghost_follow_link(speaker, M)]) [message_body]"
|
||||
if(M.check_mentioned(message) && M.is_preference_enabled(/datum/client_preference/check_mention))
|
||||
message_to_send = "<font size='3'><b>[message_to_send]</b></font>"
|
||||
M.show_message(message_to_send, 2)
|
||||
|
||||
for (var/mob/living/S in living_mob_list)
|
||||
|
||||
if(drone_only && !istype(S,/mob/living/silicon/robot/drone))
|
||||
continue
|
||||
else if(istype(S , /mob/living/silicon/ai))
|
||||
@@ -33,7 +37,10 @@
|
||||
else if (!S.binarycheck())
|
||||
continue
|
||||
|
||||
S.show_message("[message_start] [message_body]", 2)
|
||||
var/message_to_send = "[message_start] [message_body]"
|
||||
if(S.check_mentioned(message) && S.is_preference_enabled(/datum/client_preference/check_mention))
|
||||
message_to_send = "<font size='3'><b>[message_to_send]</b></font>"
|
||||
S.show_message(message_to_send, 2)
|
||||
|
||||
var/list/listening = hearers(1, src)
|
||||
listening -= src
|
||||
|
||||
@@ -59,6 +59,8 @@
|
||||
/datum/species/proc/handle_autohiss(message, datum/language/lang, mode)
|
||||
if(!autohiss_basic_map)
|
||||
return message
|
||||
if(lang.flags & NO_STUTTER) // Currently prevents EAL, Sign language, and emotes from autohissing
|
||||
return message
|
||||
if(autohiss_exempt && (lang.name in autohiss_exempt))
|
||||
return message
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
var/turf/obstacle = null
|
||||
|
||||
var/wait_if_pulled = 0 // Only applies to moving to the target
|
||||
var/will_patrol = 0 // Not a setting - whether or no this type of bots patrols at all
|
||||
var/will_patrol = 0 // If set to 1, will patrol, duh
|
||||
var/patrol_speed = 1 // How many times per tick we move when patrolling
|
||||
var/target_speed = 2 // Ditto for chasing the target
|
||||
var/min_target_dist = 1 // How close we try to get to the target
|
||||
@@ -49,7 +49,11 @@
|
||||
access_scanner.req_access = req_access.Copy()
|
||||
access_scanner.req_one_access = req_one_access.Copy()
|
||||
|
||||
turn_on()
|
||||
// Make sure mapped in units start turned on.
|
||||
/mob/living/bot/initialize()
|
||||
..()
|
||||
if(on)
|
||||
turn_on() // Update lights and other stuff
|
||||
|
||||
/mob/living/bot/Life()
|
||||
..()
|
||||
@@ -61,7 +65,8 @@
|
||||
paralysis = 0
|
||||
|
||||
if(on && !client && !busy)
|
||||
handleAI()
|
||||
spawn(0)
|
||||
handleAI()
|
||||
|
||||
/mob/living/bot/updatehealth()
|
||||
if(status_flags & GODMODE)
|
||||
@@ -145,20 +150,18 @@
|
||||
handleRangedTarget()
|
||||
if(!wait_if_pulled || !pulledby)
|
||||
for(var/i = 1 to target_speed)
|
||||
sleep(20 / (target_speed + 1))
|
||||
stepToTarget()
|
||||
if(i < target_speed)
|
||||
sleep(20 / target_speed)
|
||||
if(max_frustration && frustration > max_frustration * target_speed)
|
||||
handleFrustrated(1)
|
||||
else
|
||||
resetTarget()
|
||||
lookForTargets()
|
||||
if(will_patrol && !pulledby && !target)
|
||||
if(patrol_path.len)
|
||||
if(patrol_path && patrol_path.len)
|
||||
for(var/i = 1 to patrol_speed)
|
||||
sleep(20 / (patrol_speed + 1))
|
||||
handlePatrol()
|
||||
if(i < patrol_speed)
|
||||
sleep(20 / patrol_speed)
|
||||
if(max_frustration && frustration > max_frustration * patrol_speed)
|
||||
handleFrustrated(0)
|
||||
else
|
||||
@@ -219,6 +222,25 @@
|
||||
return
|
||||
|
||||
/mob/living/bot/proc/getPatrolTurf()
|
||||
var/minDist = INFINITY
|
||||
var/obj/machinery/navbeacon/targ = locate() in get_turf(src)
|
||||
|
||||
if(!targ)
|
||||
for(var/obj/machinery/navbeacon/N in navbeacons)
|
||||
if(!N.codes["patrol"])
|
||||
continue
|
||||
if(get_dist(src, N) < minDist)
|
||||
minDist = get_dist(src, N)
|
||||
targ = N
|
||||
|
||||
if(targ && targ.codes["next_patrol"])
|
||||
for(var/obj/machinery/navbeacon/N in navbeacons)
|
||||
if(N.location == targ.codes["next_patrol"])
|
||||
targ = N
|
||||
break
|
||||
|
||||
if(targ)
|
||||
return get_turf(targ)
|
||||
return null
|
||||
|
||||
/mob/living/bot/proc/handleIdle()
|
||||
@@ -255,15 +277,16 @@
|
||||
on = 1
|
||||
set_light(light_strength)
|
||||
update_icons()
|
||||
resetTarget()
|
||||
patrol_path = list()
|
||||
ignore_list = list()
|
||||
return 1
|
||||
|
||||
/mob/living/bot/proc/turn_off()
|
||||
on = 0
|
||||
busy = 0 // If ever stuck... reboot!
|
||||
set_light(0)
|
||||
update_icons()
|
||||
resetTarget()
|
||||
patrol_path = list()
|
||||
ignore_list = list()
|
||||
|
||||
/mob/living/bot/proc/explode()
|
||||
qdel(src)
|
||||
@@ -327,6 +350,11 @@
|
||||
|
||||
for(var/obj/machinery/door/D in loc)
|
||||
if(!D.density) continue
|
||||
|
||||
if(istype(D, /obj/machinery/door/airlock))
|
||||
var/obj/machinery/door/airlock/A = D
|
||||
if(!A.can_open()) return 1
|
||||
|
||||
if(istype(D, /obj/machinery/door/window))
|
||||
if( dir & D.dir ) return !D.check_access(ID)
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
var/cleaning = 0
|
||||
var/screwloose = 0
|
||||
var/oddbutton = 0
|
||||
var/should_patrol = 0
|
||||
var/blood = 1
|
||||
var/list/target_types = list()
|
||||
|
||||
@@ -32,9 +31,11 @@
|
||||
if(oddbutton && prob(5)) // Make a big mess
|
||||
visible_message("Something flies out of [src]. He seems to be acting oddly.")
|
||||
var/obj/effect/decal/cleanable/blood/gibs/gib = new /obj/effect/decal/cleanable/blood/gibs(loc)
|
||||
ignore_list += gib
|
||||
// TODO - I have a feeling weakrefs will not work in ignore_list, verify this ~Leshana
|
||||
var/weakref/g = weakref(gib)
|
||||
ignore_list += g
|
||||
spawn(600)
|
||||
ignore_list -= gib
|
||||
ignore_list -= g
|
||||
|
||||
/mob/living/bot/cleanbot/lookForTargets()
|
||||
for(var/obj/effect/decal/cleanable/D in view(world.view, src)) // There was some odd code to make it start with nearest decals, it's unnecessary, this works
|
||||
@@ -110,7 +111,7 @@
|
||||
dat += "Maintenance panel is [open ? "opened" : "closed"]"
|
||||
if(!locked || issilicon(user))
|
||||
dat += "<BR>Cleans Blood: <A href='?src=\ref[src];operation=blood'>[blood ? "Yes" : "No"]</A><BR>"
|
||||
dat += "<BR>Patrol station: <A href='?src=\ref[src];operation=patrol'>[should_patrol ? "Yes" : "No"]</A><BR>"
|
||||
dat += "<BR>Patrol station: <A href='?src=\ref[src];operation=patrol'>[will_patrol ? "Yes" : "No"]</A><BR>"
|
||||
if(open && !locked)
|
||||
dat += "Odd looking screw twiddled: <A href='?src=\ref[src];operation=screw'>[screwloose ? "Yes" : "No"]</A><BR>"
|
||||
dat += "Weird button pressed: <A href='?src=\ref[src];operation=oddbutton'>[oddbutton ? "Yes" : "No"]</A>"
|
||||
@@ -134,7 +135,7 @@
|
||||
blood = !blood
|
||||
get_targets()
|
||||
if("patrol")
|
||||
should_patrol = !should_patrol
|
||||
will_patrol = !will_patrol
|
||||
patrol_path = null
|
||||
if("screw")
|
||||
screwloose = !screwloose
|
||||
|
||||
@@ -170,7 +170,7 @@
|
||||
visible_message("<span class='notice'>[src] starts [T.dead? "removing the plant from" : "harvesting"] \the [A].</span>")
|
||||
|
||||
busy = 1
|
||||
if(do_after(src, 30))
|
||||
if(do_after(src, 30, A))
|
||||
visible_message("<span class='notice'>[src] [T.dead? "removes the plant from" : "harvests"] \the [A].</span>")
|
||||
T.attack_hand(src)
|
||||
if(FARMBOT_WATER)
|
||||
@@ -179,7 +179,7 @@
|
||||
visible_message("<span class='notice'>[src] starts watering \the [A].</span>")
|
||||
|
||||
busy = 1
|
||||
if(do_after(src, 30))
|
||||
if(do_after(src, 30, A))
|
||||
playsound(loc, 'sound/effects/slosh.ogg', 25, 1)
|
||||
visible_message("<span class='notice'>[src] waters \the [A].</span>")
|
||||
tank.reagents.trans_to(T, 100 - T.waterlevel)
|
||||
@@ -198,7 +198,7 @@
|
||||
visible_message("<span class='notice'>[src] starts fertilizing \the [A].</span>")
|
||||
|
||||
busy = 1
|
||||
if(do_after(src, 30))
|
||||
if(do_after(src, 30, A))
|
||||
|
||||
visible_message("<span class='notice'>[src] fertilizes \the [A].</span>")
|
||||
T.reagents.add_reagent("ammonia", 10)
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
// Configure whether or not floorbot will fix hull breaches.
|
||||
// This can be a problem if it tries to pave over space or shuttles. That should be fixed but...
|
||||
// If it can see space outside windows, it can be laggy since it keeps wondering if it should fix them.
|
||||
// Therefore that functionality is disabled for now. But it can be turned on by uncommenting this.
|
||||
// #define FLOORBOT_PATCHES_HOLES 1
|
||||
|
||||
/mob/living/bot/floorbot
|
||||
name = "Floorbot"
|
||||
desc = "A little floor repairing robot, he looks so excited!"
|
||||
@@ -25,7 +31,7 @@
|
||||
|
||||
/mob/living/bot/floorbot/attack_hand(var/mob/user)
|
||||
user.set_machine(src)
|
||||
var/dat
|
||||
var/list/dat = list()
|
||||
dat += "<TT><B>Automatic Station Floor Repairer v1.0</B></TT><BR><BR>"
|
||||
dat += "Status: <A href='?src=\ref[src];operation=start'>[src.on ? "On" : "Off"]</A><BR>"
|
||||
dat += "Maintenance panel is [open ? "opened" : "closed"]<BR>"
|
||||
@@ -41,9 +47,9 @@
|
||||
else
|
||||
bmode = "Disabled"
|
||||
dat += "<BR><BR>Bridge Mode : <A href='?src=\ref[src];operation=bridgemode'>[bmode]</A><BR>"
|
||||
|
||||
user << browse("<HEAD><TITLE>Repairbot v1.0 controls</TITLE></HEAD>[dat]", "window=autorepair")
|
||||
onclose(user, "autorepair")
|
||||
var/datum/browser/popup = new(user, "autorepair", "Repairbot v1.1 controls")
|
||||
popup.set_content(jointext(dat,null))
|
||||
popup.open()
|
||||
return
|
||||
|
||||
/mob/living/bot/floorbot/emag_act(var/remaining_charges, var/mob/user)
|
||||
@@ -115,23 +121,24 @@
|
||||
target = T
|
||||
return
|
||||
T = get_step(T, targetdirection)
|
||||
return // In bridge mode we don't want to step off that line even to eat plates!
|
||||
|
||||
else // Fixing floors
|
||||
for(var/turf/space/T in view(src)) // Breaches are of higher priority
|
||||
if(confirmTarget(T))
|
||||
target = T
|
||||
return
|
||||
#ifdef FLOORBOT_PATCHES_HOLES
|
||||
for(var/turf/space/T in view(src)) // Breaches are of higher priority
|
||||
if(confirmTarget(T))
|
||||
target = T
|
||||
return
|
||||
|
||||
for(var/turf/simulated/mineral/floor/T in view(src)) // Asteroids are of smaller priority
|
||||
if(confirmTarget(T))
|
||||
target = T
|
||||
return
|
||||
|
||||
if(improvefloors)
|
||||
for(var/turf/simulated/floor/T in view(src))
|
||||
if(confirmTarget(T))
|
||||
target = T
|
||||
return
|
||||
for(var/turf/simulated/mineral/floor/T in view(src)) // Asteroids are of smaller priority
|
||||
if(confirmTarget(T))
|
||||
target = T
|
||||
return
|
||||
#endif
|
||||
// Look for broken floors even if we aren't improvefloors
|
||||
for(var/turf/simulated/floor/T in view(src))
|
||||
if(confirmTarget(T))
|
||||
target = T
|
||||
return
|
||||
|
||||
if(amount < maxAmount && (eattiles || maketiles))
|
||||
for(var/obj/item/stack/S in view(src))
|
||||
@@ -148,7 +155,11 @@
|
||||
if(istype(A, /obj/item/stack/material/steel))
|
||||
return (amount < maxAmount && maketiles)
|
||||
|
||||
if(A.loc.name == "Space")
|
||||
// Don't pave over all of space, build there only if in bridge mode
|
||||
if(!targetdirection && istype(A.loc, /area/space)) // Note name == "Space" does not work!
|
||||
return 0
|
||||
|
||||
if(istype(A.loc, /area/shuttle)) // Do NOT mess with shuttle drop zones
|
||||
return 0
|
||||
|
||||
if(emagged)
|
||||
@@ -157,14 +168,16 @@
|
||||
if(!amount)
|
||||
return 0
|
||||
|
||||
#ifdef FLOORBOT_PATCHES_HOLES
|
||||
if(istype(A, /turf/space))
|
||||
return 1
|
||||
|
||||
if(istype(A, /turf/simulated/mineral/floor))
|
||||
return 1
|
||||
#endif
|
||||
|
||||
var/turf/simulated/floor/T = A
|
||||
return (istype(T) && improvefloors && !T.flooring && (get_turf(T) == loc || prob(40)))
|
||||
return (istype(T) && (T.broken || T.burnt || (improvefloors && !T.flooring)) && (get_turf(T) == loc || prob(40)))
|
||||
|
||||
/mob/living/bot/floorbot/UnarmedAttack(var/atom/A, var/proximity)
|
||||
if(!..())
|
||||
@@ -181,12 +194,12 @@
|
||||
busy = 1
|
||||
update_icons()
|
||||
if(F.flooring)
|
||||
visible_message("<span class='warning'>[src] begins to tear the floor tile from the floor!</span>")
|
||||
visible_message("<span class='warning'>\The [src] begins to tear the floor tile from the floor!</span>")
|
||||
if(do_after(src, 50))
|
||||
F.break_tile_to_plating()
|
||||
addTiles(1)
|
||||
else
|
||||
visible_message("<span class='danger'>[src] begins to tear through the floor!</span>")
|
||||
visible_message("<span class='danger'>\The [src] begins to tear through the floor!</span>")
|
||||
if(do_after(src, 150)) // Extra time because this can and will kill.
|
||||
F.ReplaceWithLattice()
|
||||
addTiles(1)
|
||||
@@ -201,7 +214,7 @@
|
||||
return
|
||||
busy = 1
|
||||
update_icons()
|
||||
visible_message("<span class='notice'>[src] begins to repair the hole.</span>")
|
||||
visible_message("<span class='notice'>\The [src] begins to repair the hole.</span>")
|
||||
if(do_after(src, 50))
|
||||
if(A && (locate(/obj/structure/lattice, A) && building == 1 || !locate(/obj/structure/lattice, A) && building == 2)) // Make sure that it still needs repairs
|
||||
var/obj/item/I
|
||||
@@ -215,10 +228,20 @@
|
||||
update_icons()
|
||||
else if(istype(A, /turf/simulated/floor))
|
||||
var/turf/simulated/floor/F = A
|
||||
if(!F.flooring && amount)
|
||||
if(F.broken || F.burnt)
|
||||
busy = 1
|
||||
update_icons()
|
||||
visible_message("<span class='notice'>[src] begins to improve the floor.</span>")
|
||||
visible_message("<span class='notice'>\The [src] begins to remove the broken floor.</span>")
|
||||
if(do_after(src, 50, F))
|
||||
if(F.broken || F.burnt)
|
||||
F.make_plating()
|
||||
target = null
|
||||
busy = 0
|
||||
update_icons()
|
||||
else if(!F.flooring && amount)
|
||||
busy = 1
|
||||
update_icons()
|
||||
visible_message("<span class='notice'>\The [src] begins to improve the floor.</span>")
|
||||
if(do_after(src, 50))
|
||||
if(!F.flooring)
|
||||
F.set_flooring(get_flooring_data(floor_build_type))
|
||||
@@ -228,7 +251,7 @@
|
||||
update_icons()
|
||||
else if(istype(A, /obj/item/stack/tile/floor) && amount < maxAmount)
|
||||
var/obj/item/stack/tile/floor/T = A
|
||||
visible_message("<span class='notice'>[src] begins to collect tiles.</span>")
|
||||
visible_message("<span class='notice'>\The [src] begins to collect tiles.</span>")
|
||||
busy = 1
|
||||
update_icons()
|
||||
if(do_after(src, 20))
|
||||
@@ -242,7 +265,7 @@
|
||||
else if(istype(A, /obj/item/stack/material) && amount + 4 <= maxAmount)
|
||||
var/obj/item/stack/material/M = A
|
||||
if(M.get_material_name() == DEFAULT_WALL_MATERIAL)
|
||||
visible_message("<span class='notice'>[src] begins to make tiles.</span>")
|
||||
visible_message("<span class='notice'>\The [src] begins to make tiles.</span>")
|
||||
busy = 1
|
||||
update_icons()
|
||||
if(do_after(50))
|
||||
@@ -252,7 +275,7 @@
|
||||
|
||||
/mob/living/bot/floorbot/explode()
|
||||
turn_off()
|
||||
visible_message("<span class='danger'>[src] blows apart!</span>")
|
||||
visible_message("<span class='danger'>\The [src] blows apart!</span>")
|
||||
var/turf/Tsec = get_turf(src)
|
||||
|
||||
var/obj/item/weapon/storage/toolbox/mechanical/N = new /obj/item/weapon/storage/toolbox/mechanical(Tsec)
|
||||
@@ -353,4 +376,4 @@
|
||||
return
|
||||
if(!in_range(src, user) && loc != user)
|
||||
return
|
||||
created_name = t
|
||||
created_name = t
|
||||
|
||||
@@ -130,10 +130,7 @@
|
||||
|
||||
if("sethome")
|
||||
var/new_dest
|
||||
var/list/beaconlist = new()
|
||||
for(var/obj/machinery/navbeacon/N in navbeacons)
|
||||
beaconlist.Add(N.location)
|
||||
beaconlist[N.location] = N
|
||||
var/list/beaconlist = GetBeaconList()
|
||||
if(beaconlist.len)
|
||||
new_dest = input("Select new home tag", "Mulebot [suffix ? "([suffix])" : ""]", null) in null|beaconlist
|
||||
else
|
||||
@@ -168,10 +165,7 @@
|
||||
targetName = "Home"
|
||||
if("SetD")
|
||||
var/new_dest
|
||||
var/list/beaconlist = new()
|
||||
for(var/obj/machinery/navbeacon/N in navbeacons)
|
||||
beaconlist.Add(N.location)
|
||||
beaconlist[N.location] = N
|
||||
var/list/beaconlist = GetBeaconList()
|
||||
if(beaconlist.len)
|
||||
new_dest = input("Select new destination tag", "Mulebot [suffix ? "([suffix])" : ""]") in null|beaconlist
|
||||
else
|
||||
@@ -285,6 +279,15 @@
|
||||
new /obj/effect/decal/cleanable/blood/oil(Tsec)
|
||||
..()
|
||||
|
||||
/mob/living/bot/mulebot/proc/GetBeaconList()
|
||||
var/list/beaconlist = list()
|
||||
for(var/obj/machinery/navbeacon/N in navbeacons)
|
||||
if(!N.codes["delivery"])
|
||||
continue
|
||||
beaconlist.Add(N.location)
|
||||
beaconlist[N.location] = N
|
||||
return beaconlist
|
||||
|
||||
/mob/living/bot/mulebot/proc/load(var/atom/movable/C)
|
||||
if(busy || load || get_dist(C, src) > 1 || !isturf(C.loc))
|
||||
return
|
||||
@@ -304,11 +307,11 @@
|
||||
|
||||
busy = 1
|
||||
|
||||
C.loc = loc
|
||||
C.forceMove(loc)
|
||||
sleep(2)
|
||||
if(C.loc != loc) //To prevent you from going onto more than one bot.
|
||||
return
|
||||
C.loc = src
|
||||
C.forceMove(src)
|
||||
load = C
|
||||
|
||||
C.pixel_y += 9
|
||||
@@ -325,7 +328,7 @@
|
||||
busy = 1
|
||||
overlays.Cut()
|
||||
|
||||
load.loc = loc
|
||||
load.forceMove(loc)
|
||||
load.pixel_y -= 9
|
||||
load.layer = initial(load.layer)
|
||||
|
||||
@@ -338,7 +341,7 @@
|
||||
if(AM == botcard || AM == access_scanner)
|
||||
continue
|
||||
|
||||
AM.loc = loc
|
||||
AM.forceMove(loc)
|
||||
AM.layer = initial(AM.layer)
|
||||
AM.pixel_y = initial(AM.pixel_y)
|
||||
busy = 0
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
#define SECBOT_WAIT_TIME 5 //number of in-game seconds to wait for someone to surrender
|
||||
#define SECBOT_THREAT_ARREST 4 //threat level at which we decide to arrest someone
|
||||
#define SECBOT_THREAT_ATTACK 8 //threat level at which was assume immediate danger and attack right away
|
||||
|
||||
/mob/living/bot/secbot
|
||||
name = "Securitron"
|
||||
desc = "A little security robot. He looks less than thrilled."
|
||||
icon_state = "secbot0"
|
||||
maxHealth = 100
|
||||
health = 100
|
||||
req_one_access = list(access_robotics, access_security, access_forensics_lockers)
|
||||
req_one_access = list(access_security, access_forensics_lockers)
|
||||
botcard_access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels)
|
||||
patrol_speed = 2
|
||||
target_speed = 3
|
||||
@@ -14,18 +18,17 @@
|
||||
var/check_arrest = 1 // If true, arrests people who are set to arrest.
|
||||
var/arrest_type = 0 // If true, doesn't handcuff. You monster.
|
||||
var/declare_arrests = 0 // If true, announces arrests over sechuds.
|
||||
var/auto_patrol = 0 // If true, patrols on its own
|
||||
|
||||
var/is_ranged = 0
|
||||
var/awaiting_surrender = 0
|
||||
|
||||
var/list/threat_found_sounds = new('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg')
|
||||
var/list/preparing_arrest_sounds = new('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg')
|
||||
var/list/threat_found_sounds = list('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg')
|
||||
var/list/preparing_arrest_sounds = list('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/bcreep.ogg')
|
||||
|
||||
/mob/living/bot/secbot/beepsky
|
||||
name = "Officer Beepsky"
|
||||
desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
|
||||
auto_patrol = 1
|
||||
will_patrol = 1
|
||||
|
||||
/mob/living/bot/secbot/update_icons()
|
||||
if(on && busy)
|
||||
@@ -40,7 +43,7 @@
|
||||
|
||||
/mob/living/bot/secbot/attack_hand(var/mob/user)
|
||||
user.set_machine(src)
|
||||
var/dat
|
||||
var/list/dat = list()
|
||||
dat += "<TT><B>Automatic Security Unit</B></TT><BR><BR>"
|
||||
dat += "Status: <A href='?src=\ref[src];power=1'>[on ? "On" : "Off"]</A><BR>"
|
||||
dat += "Behaviour controls are [locked ? "locked" : "unlocked"]<BR>"
|
||||
@@ -51,10 +54,10 @@
|
||||
dat += "Check Arrest Status: <A href='?src=\ref[src];operation=ignorearr'>[check_arrest ? "Yes" : "No"]</A><BR>"
|
||||
dat += "Operating Mode: <A href='?src=\ref[src];operation=switchmode'>[arrest_type ? "Detain" : "Arrest"]</A><BR>"
|
||||
dat += "Report Arrests: <A href='?src=\ref[src];operation=declarearrests'>[declare_arrests ? "Yes" : "No"]</A><BR>"
|
||||
dat += "Auto Patrol: <A href='?src=\ref[src];operation=patrol'>[auto_patrol ? "On" : "Off"]</A>"
|
||||
user << browse("<HEAD><TITLE>Securitron controls</TITLE></HEAD>[dat]", "window=autosec")
|
||||
onclose(user, "autosec")
|
||||
return
|
||||
dat += "Auto Patrol: <A href='?src=\ref[src];operation=patrol'>[will_patrol ? "On" : "Off"]</A>"
|
||||
var/datum/browser/popup = new(user, "autosec", "Securitron controls")
|
||||
popup.set_content(jointext(dat,null))
|
||||
popup.open()
|
||||
|
||||
/mob/living/bot/secbot/Topic(href, href_list)
|
||||
if(..())
|
||||
@@ -80,7 +83,7 @@
|
||||
if("switchmode")
|
||||
arrest_type = !arrest_type
|
||||
if("patrol")
|
||||
auto_patrol = !auto_patrol
|
||||
will_patrol = !will_patrol
|
||||
if("declarearrests")
|
||||
declare_arrests = !declare_arrests
|
||||
attack_hand(usr)
|
||||
@@ -99,10 +102,46 @@
|
||||
|
||||
/mob/living/bot/secbot/attackby(var/obj/item/O, var/mob/user)
|
||||
var/curhealth = health
|
||||
..()
|
||||
. = ..()
|
||||
if(health < curhealth)
|
||||
target = user
|
||||
awaiting_surrender = 5
|
||||
react_to_attack(user)
|
||||
|
||||
/mob/living/bot/secbot/bullet_act(var/obj/item/projectile/P)
|
||||
var/curhealth = health
|
||||
var/mob/shooter = P.firer
|
||||
. = ..()
|
||||
//if we already have a target just ignore to avoid lots of checking
|
||||
if(!target && health < curhealth && shooter && (shooter in view(world.view, src)))
|
||||
react_to_attack(shooter)
|
||||
|
||||
/mob/living/bot/secbot/proc/react_to_attack(mob/attacker)
|
||||
if(!target)
|
||||
playsound(src.loc, pick(threat_found_sounds), 50)
|
||||
broadcast_security_hud_message("[src] was attacked by a hostile <b>[target_name(attacker)]</b> in <b>[get_area(src)]</b>.", src)
|
||||
target = attacker
|
||||
awaiting_surrender = INFINITY // Don't try and wait for surrender
|
||||
|
||||
// Say "freeze!" and demand surrender
|
||||
/mob/living/bot/secbot/proc/demand_surrender(mob/target, var/threat)
|
||||
var/suspect_name = target_name(target)
|
||||
if(declare_arrests)
|
||||
broadcast_security_hud_message("[src] is [arrest_type ? "detaining" : "arresting"] a level [threat] suspect <b>[suspect_name]</b> in <b>[get_area(src)]</b>.", src)
|
||||
say("Down on the floor, [suspect_name]! You have [SECBOT_WAIT_TIME] seconds to comply.")
|
||||
playsound(src.loc, pick(preparing_arrest_sounds), 50)
|
||||
// Register to be told when the target moves
|
||||
moved_event.register(target, src, /mob/living/bot/secbot/proc/target_moved)
|
||||
|
||||
// Callback invoked if the registered target moves
|
||||
/mob/living/bot/secbot/proc/target_moved(atom/movable/moving_instance, atom/old_loc, atom/new_loc)
|
||||
if(get_dist(get_turf(src), get_turf(target)) >= 1)
|
||||
awaiting_surrender = INFINITY // Done waiting!
|
||||
moved_event.unregister(moving_instance, src)
|
||||
|
||||
/mob/living/bot/secbot/resetTarget()
|
||||
..()
|
||||
moved_event.unregister(target, src)
|
||||
awaiting_surrender = -1
|
||||
walk_to(src, 0)
|
||||
|
||||
/mob/living/bot/secbot/startPatrol()
|
||||
if(!locked) // Stop running away when we set you up
|
||||
@@ -112,8 +151,7 @@
|
||||
/mob/living/bot/secbot/confirmTarget(var/atom/A)
|
||||
if(!..())
|
||||
return 0
|
||||
|
||||
return (check_threat(A) > 3)
|
||||
return (check_threat(A) >= SECBOT_THREAT_ARREST)
|
||||
|
||||
/mob/living/bot/secbot/lookForTargets()
|
||||
for(var/mob/living/M in view(src))
|
||||
@@ -127,23 +165,17 @@
|
||||
custom_emote(1, "points at [M.name]!")
|
||||
return
|
||||
|
||||
/mob/living/bot/secbot/calcTargetPath()
|
||||
..()
|
||||
if(awaiting_surrender != -1)
|
||||
awaiting_surrender = 5 // This implies that a) we have already approached the target and b) it has moved after the warning
|
||||
|
||||
/mob/living/bot/secbot/handleAdjacentTarget()
|
||||
if(awaiting_surrender < 5 && ishuman(target) && !target:lying)
|
||||
if(awaiting_surrender == -1)
|
||||
say("Down on the floor, [target]! You have five seconds to comply.")
|
||||
var/mob/living/carbon/human/H = target
|
||||
var/threat = check_threat(target)
|
||||
if(awaiting_surrender < SECBOT_WAIT_TIME && istype(H) && !H.lying && threat < SECBOT_THREAT_ATTACK)
|
||||
if(awaiting_surrender == -1) // On first tick of awaiting...
|
||||
demand_surrender(target, threat)
|
||||
++awaiting_surrender
|
||||
else
|
||||
if(declare_arrests)
|
||||
broadcast_security_hud_message("[src] is [arrest_type ? "detaining" : "arresting"] a level [threat] suspect <b>[target_name(target)]</b> in <b>[get_area(src)]</b>.", src)
|
||||
UnarmedAttack(target)
|
||||
if(ishuman(target) && declare_arrests)
|
||||
var/area/location = get_area(src)
|
||||
broadcast_security_hud_message("[src] is [arrest_type ? "detaining" : "arresting"] a level [check_threat(target)] suspect <b>[target]</b> in <b>[location]</b>.", src)
|
||||
|
||||
// say("Engaging patrol mode.")
|
||||
|
||||
/mob/living/bot/secbot/UnarmedAttack(var/mob/M, var/proximity)
|
||||
if(!..())
|
||||
@@ -170,17 +202,15 @@
|
||||
spawn(2)
|
||||
busy = 0
|
||||
update_icons()
|
||||
visible_message("<span class='warning'>[C] was prodded by [src] with a stun baton!</span>")
|
||||
visible_message("<span class='warning'>\The [C] was prodded by \the [src] with a stun baton!</span>")
|
||||
else
|
||||
playsound(loc, 'sound/weapons/handcuffs.ogg', 30, 1, -2)
|
||||
visible_message("<span class='warning'>[src] is trying to put handcuffs on [C]!</span>")
|
||||
visible_message("<span class='warning'>\The [src] is trying to put handcuffs on \the [C]!</span>")
|
||||
busy = 1
|
||||
if(do_mob(src, C, 60))
|
||||
if(!C.handcuffed)
|
||||
C.handcuffed = new /obj/item/weapon/handcuffs(C)
|
||||
C.update_inv_handcuffed()
|
||||
if(preparing_arrest_sounds.len)
|
||||
playsound(loc, pick(preparing_arrest_sounds), 50, 0)
|
||||
busy = 0
|
||||
else if(istype(M, /mob/living/simple_animal))
|
||||
var/mob/living/simple_animal/S = M
|
||||
@@ -193,7 +223,8 @@
|
||||
spawn(2)
|
||||
busy = 0
|
||||
update_icons()
|
||||
visible_message("<span class='warning'>[M] was beaten by [src] with a stun baton!</span>")
|
||||
visible_message("<span class='warning'>\The [M] was beaten by \the [src] with a stun baton!</span>")
|
||||
|
||||
|
||||
/mob/living/bot/secbot/explode()
|
||||
visible_message("<span class='warning'>[src] blows apart!</span>")
|
||||
@@ -215,11 +246,17 @@
|
||||
new /obj/effect/decal/cleanable/blood/oil(Tsec)
|
||||
qdel(src)
|
||||
|
||||
/mob/living/bot/secbot/proc/target_name(mob/living/T)
|
||||
if(ishuman(T))
|
||||
var/mob/living/carbon/human/H = T
|
||||
return H.get_id_name("unidentified person")
|
||||
return "unidentified lifeform"
|
||||
|
||||
/mob/living/bot/secbot/proc/check_threat(var/mob/living/M)
|
||||
if(!M || !istype(M) || M.stat == DEAD || src == M)
|
||||
return 0
|
||||
|
||||
if(emagged)
|
||||
if(emagged && !M.incapacitated()) //check incapacitated so emagged secbots don't keep attacking the same target forever
|
||||
return 10
|
||||
|
||||
return M.assess_perp(access_scanner, 0, idcheck, check_records, check_arrest)
|
||||
@@ -297,4 +334,4 @@
|
||||
return
|
||||
if(!in_range(src, usr) && loc != usr)
|
||||
return
|
||||
created_name = t
|
||||
created_name = t
|
||||
|
||||
@@ -164,7 +164,9 @@
|
||||
if(2)
|
||||
brainmob.emp_damage += rand(10,20)
|
||||
if(3)
|
||||
brainmob.emp_damage += rand(0,10)
|
||||
brainmob.emp_damage += rand(5,10)
|
||||
if(4)
|
||||
brainmob.emp_damage += rand(0,5)
|
||||
..()
|
||||
|
||||
/obj/item/device/mmi/digital
|
||||
@@ -216,7 +218,9 @@
|
||||
if(2)
|
||||
src.brainmob.emp_damage += rand(10,20)
|
||||
if(3)
|
||||
src.brainmob.emp_damage += rand(0,10)
|
||||
src.brainmob.emp_damage += rand(5,10)
|
||||
if(4)
|
||||
src.brainmob.emp_damage += rand(0,5)
|
||||
..()
|
||||
|
||||
/obj/item/device/mmi/digital/transfer_identity(var/mob/living/carbon/H)
|
||||
|
||||
@@ -112,7 +112,9 @@
|
||||
if(2)
|
||||
src.brainmob.emp_damage += rand(10,20)
|
||||
if(3)
|
||||
src.brainmob.emp_damage += rand(0,10)
|
||||
src.brainmob.emp_damage += rand(5,10)
|
||||
if(4)
|
||||
src.brainmob.emp_damage += rand(0,5)
|
||||
..()
|
||||
|
||||
/obj/item/device/mmi/digital/posibrain/New()
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
message = "is strumming the air and headbanging like a safari chimp."
|
||||
m_type = 1
|
||||
|
||||
if("ping", "beep", "buzz", "yes", "no")
|
||||
//Machine-only emotes
|
||||
if("ping", "beep", "buzz", "yes", "no", "rcough", "rsneeze")
|
||||
|
||||
if(!isSynthetic())
|
||||
src << "<span class='warning'>You are not a synthetic.</span>"
|
||||
@@ -54,6 +55,18 @@
|
||||
else if(act == "no")
|
||||
display_msg = "emits a negative blip"
|
||||
use_sound = 'sound/machines/synth_no.ogg'
|
||||
else if(act == "rcough")
|
||||
display_msg = "emits a robotic cough"
|
||||
if(gender == FEMALE)
|
||||
use_sound = pick('sound/effects/mob_effects/f_machine_cougha.ogg','sound/effects/mob_effects/f_machine_coughb.ogg')
|
||||
else
|
||||
use_sound = pick('sound/effects/mob_effects/m_machine_cougha.ogg','sound/effects/mob_effects/m_machine_coughb.ogg', 'sound/effects/mob_effects/m_machine_coughc.ogg')
|
||||
else if(act == "rsneeze")
|
||||
display_msg = "emits a robotic sneeze"
|
||||
if(gender == FEMALE)
|
||||
use_sound = 'sound/effects/mob_effects/machine_sneeze.ogg'
|
||||
else
|
||||
use_sound = 'sound/effects/mob_effects/f_machine_sneeze.ogg'
|
||||
|
||||
if (param)
|
||||
message = "[display_msg] at [param]."
|
||||
@@ -62,6 +75,17 @@
|
||||
playsound(src.loc, use_sound, 50, 0)
|
||||
m_type = 1
|
||||
|
||||
//Promethean-only emotes
|
||||
if("squish")
|
||||
if(!species.bump_flag == SLIME) //That should do, yaya.
|
||||
src << "<span class='warning'>You are not a slime thing!</span>"
|
||||
return
|
||||
|
||||
playsound(src.loc, 'sound/effects/slime_squish.ogg', 50, 0) //Credit to DrMinky (freesound.org) for the sound.
|
||||
message = "blinks."
|
||||
m_type = 1
|
||||
|
||||
|
||||
if ("blink")
|
||||
message = "blinks."
|
||||
m_type = 1
|
||||
@@ -202,14 +226,20 @@
|
||||
src.sleeping += 10 //Short-short nap
|
||||
m_type = 1
|
||||
|
||||
if ("cough")
|
||||
if("cough", "coughs")
|
||||
if(miming)
|
||||
message = "appears to cough!"
|
||||
m_type = 1
|
||||
else
|
||||
if (!muzzled)
|
||||
if(!muzzled)
|
||||
message = "coughs!"
|
||||
m_type = 2
|
||||
if(gender == FEMALE)
|
||||
if(species.female_cough_sounds)
|
||||
playsound(src, pick(species.female_cough_sounds), 120)
|
||||
else
|
||||
if(species.male_cough_sounds)
|
||||
playsound(src, pick(species.male_cough_sounds), 120)
|
||||
else
|
||||
message = "makes a strong noise."
|
||||
m_type = 2
|
||||
@@ -456,13 +486,17 @@
|
||||
message = "trembles in fear!"
|
||||
m_type = 1
|
||||
|
||||
if ("sneeze")
|
||||
if (miming)
|
||||
if("sneeze", "sneezes")
|
||||
if(miming)
|
||||
message = "sneezes."
|
||||
m_type = 1
|
||||
else
|
||||
if (!muzzled)
|
||||
if(!muzzled)
|
||||
message = "sneezes."
|
||||
if(gender == FEMALE)
|
||||
playsound(src, species.female_sneeze_sound, 70)
|
||||
else
|
||||
playsound(src, species.male_sneeze_sound, 70)
|
||||
m_type = 2
|
||||
else
|
||||
message = "makes a strange noise."
|
||||
@@ -565,18 +599,59 @@
|
||||
else
|
||||
message = "sadly can't find anybody to give daps to, and daps [get_visible_gender() == MALE ? "himself" : get_visible_gender() == FEMALE ? "herself" : "themselves"]. Shameful."
|
||||
|
||||
if ("scream")
|
||||
if (miming)
|
||||
if("slap", "slaps")
|
||||
m_type = 1
|
||||
if(!restrained())
|
||||
var/M = null
|
||||
if(param)
|
||||
for(var/mob/A in view(1, null))
|
||||
if(param == A.name)
|
||||
M = A
|
||||
break
|
||||
if(M)
|
||||
message = "<span class='danger'>slaps [M] across the face. Ouch!</span>"
|
||||
playsound(loc, 'sound/effects/snap.ogg', 50, 1)
|
||||
else
|
||||
message = "<span class='danger'>slaps [get_visible_gender() == MALE ? "himself" : get_visible_gender() == FEMALE ? "herself" : "themselves"]!</span>"
|
||||
playsound(loc, 'sound/effects/snap.ogg', 50, 1)
|
||||
|
||||
if("scream", "screams")
|
||||
if(miming)
|
||||
message = "acts out a scream!"
|
||||
m_type = 1
|
||||
else
|
||||
if (!muzzled)
|
||||
message = "screams!"
|
||||
if(!muzzled)
|
||||
message = "[species.scream_verb]!"
|
||||
m_type = 2
|
||||
/* Removed, pending the location of some actually good, properly licensed sounds.
|
||||
if(gender == FEMALE)
|
||||
playsound(loc, "[species.female_scream_sound]", 80, 1)
|
||||
else
|
||||
playsound(loc, "[species.male_scream_sound]", 80, 1) //default to male screams if no gender is present.
|
||||
*/
|
||||
else
|
||||
message = "makes a very loud noise."
|
||||
m_type = 2
|
||||
|
||||
if("snap", "snaps")
|
||||
m_type = 2
|
||||
var/mob/living/carbon/human/H = src
|
||||
var/obj/item/organ/external/L = H.get_organ("l_hand")
|
||||
var/obj/item/organ/external/R = H.get_organ("r_hand")
|
||||
var/left_hand_good = 0
|
||||
var/right_hand_good = 0
|
||||
if(L && (!(L.status & ORGAN_DESTROYED)) && (!(L.splinted)) && (!(L.status & ORGAN_BROKEN)))
|
||||
left_hand_good = 1
|
||||
if(R && (!(R.status & ORGAN_DESTROYED)) && (!(R.splinted)) && (!(R.status & ORGAN_BROKEN)))
|
||||
right_hand_good = 1
|
||||
|
||||
if(!left_hand_good && !right_hand_good)
|
||||
to_chat(usr, "You need at least one hand in good working order to snap your fingers.")
|
||||
return
|
||||
|
||||
message = "snaps [get_visible_gender() == MALE ? "his" : get_visible_gender() == FEMALE ? "her" : "their"] fingers."
|
||||
playsound(loc, 'sound/effects/fingersnap.ogg', 50, 1, -3)
|
||||
|
||||
if("swish")
|
||||
src.animate_tail_once()
|
||||
|
||||
@@ -597,18 +672,14 @@
|
||||
return
|
||||
|
||||
if ("help")
|
||||
src << {"blink, blink_r, blush, bow-(none)/mob, burp, choke, chuckle, clap, collapse, cough, cry, custom, deathgasp, drool, eyebrow, fastsway/qwag,
|
||||
frown, gasp, giggle, glare-(none)/mob, grin, groan, grumble, handshake, hug-(none)/mob, laugh, look-(none)/mob, moan, mumble, nod, pale, point-atom,
|
||||
raise, salute, shake, shiver, shrug, sigh, signal-#1-10, smile, sneeze, sniff, snore, stare-(none)/mob, stopsway/swag, sway/wag, swish, tremble, twitch,
|
||||
twitch_v, vomit, whimper, wink, yawn"}
|
||||
src << "blink, blink_r, blush, bow-(none)/mob, burp, choke, chuckle, clap, collapse, cough, cry, custom, deathgasp, drool, eyebrow, fastsway/qwag, \
|
||||
frown, gasp, giggle, glare-(none)/mob, grin, groan, grumble, handshake, hug-(none)/mob, laugh, look-(none)/mob, moan, mumble, nod, pale, point-atom, \
|
||||
raise, salute, scream, sneeze, shake, shiver, shrug, sigh, signal-#1-10, slap-(none)/mob, smile, sneeze, sniff, snore, stare-(none)/mob, stopsway/swag, sway/wag, swish, tremble, twitch, \
|
||||
twitch_v, vomit, whimper, wink, yawn. Synthetics: beep, buzz, yes, no, rcough, rsneeze, ping"
|
||||
|
||||
else
|
||||
src << "\blue Unusable emote '[act]'. Say *help for a list."
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (message)
|
||||
log_emote("[name]/[key] : [message]")
|
||||
custom_emote(m_type,message)
|
||||
|
||||
@@ -82,6 +82,20 @@
|
||||
var/datum/gender/T = gender_datums[get_gender()]
|
||||
if(skipjumpsuit && skipface) //big suits/masks/helmets make it hard to tell their gender
|
||||
T = gender_datums[PLURAL]
|
||||
|
||||
else if(species && species.ambiguous_genders)
|
||||
var/can_detect_gender = FALSE
|
||||
if(isobserver(user)) // Ghosts are all knowing.
|
||||
can_detect_gender = TRUE
|
||||
if(issilicon(user)) // Borgs are too because science.
|
||||
can_detect_gender = TRUE
|
||||
else if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.species && istype(species, H.species))
|
||||
can_detect_gender = TRUE
|
||||
|
||||
if(!can_detect_gender)
|
||||
T = gender_datums[PLURAL] // Species with ambiguous_genders will not show their true gender upon examine if the examiner is not also the same species.
|
||||
else
|
||||
if(icon)
|
||||
msg += "\icon[icon] " //fucking BYOND: this should stop dreamseeker crashing if we -somehow- examine somebody before their icon is generated
|
||||
|
||||
@@ -22,6 +22,14 @@
|
||||
speech_sounds = list('sound/voice/shriek1.ogg')
|
||||
speech_chance = 20
|
||||
|
||||
scream_verb = "shrieks"
|
||||
male_scream_sound = 'sound/voice/shriek1.ogg'
|
||||
female_scream_sound = 'sound/voice/shriek1.ogg'
|
||||
male_cough_sounds = list('sound/voice/shriekcough.ogg')
|
||||
female_cough_sounds = list('sound/voice/shriekcough.ogg')
|
||||
male_sneeze_sound = 'sound/voice/shrieksneeze.ogg'
|
||||
female_sneeze_sound = 'sound/voice/shrieksneeze.ogg'
|
||||
|
||||
warning_low_pressure = 50
|
||||
hazard_low_pressure = 0
|
||||
|
||||
|
||||
@@ -50,6 +50,15 @@
|
||||
var/num_alternate_languages = 0 // How many secondary languages are available to select at character creation
|
||||
var/name_language = LANGUAGE_GALCOM // The language to use when determining names for this species, or null to use the first name/last name generator
|
||||
|
||||
//Soundy emotey things.
|
||||
var/scream_verb = "screams"
|
||||
var/male_scream_sound //= 'sound/goonstation/voice/male_scream.ogg' Removed due to licensing, replace!
|
||||
var/female_scream_sound //= 'sound/goonstation/voice/female_scream.ogg' Removed due to licensing, replace!
|
||||
var/male_cough_sounds = list('sound/effects/mob_effects/m_cougha.ogg','sound/effects/mob_effects/m_coughb.ogg', 'sound/effects/mob_effects/m_coughc.ogg')
|
||||
var/female_cough_sounds = list('sound/effects/mob_effects/f_cougha.ogg','sound/effects/mob_effects/f_coughb.ogg')
|
||||
var/male_sneeze_sound = 'sound/effects/mob_effects/sneeze.ogg'
|
||||
var/female_sneeze_sound = 'sound/effects/mob_effects/f_sneeze.ogg'
|
||||
|
||||
// Combat vars.
|
||||
var/total_health = 100 // Point at which the mob will enter crit.
|
||||
var/list/unarmed_types = list( // Possible unarmed attacks that the mob will use in combat,
|
||||
@@ -156,6 +165,7 @@
|
||||
)
|
||||
|
||||
var/list/genders = list(MALE, FEMALE)
|
||||
var/ambiguous_genders = FALSE // If true, people examining a member of this species whom are not also the same species will see them as gender neutral. Because aliens.
|
||||
|
||||
// Bump vars
|
||||
var/bump_flag = HUMAN // What are we considered to be when bumped?
|
||||
|
||||
@@ -28,6 +28,9 @@ var/datum/species/shapeshifter/promethean/prometheans
|
||||
breath_type = null
|
||||
poison_type = null
|
||||
|
||||
male_cough_sounds = list('sound/effects/slime_squish.ogg')
|
||||
female_cough_sounds = list('sound/effects/slime_squish.ogg')
|
||||
|
||||
gluttonous = 1
|
||||
virus_immune = 1
|
||||
blood_volume = 560
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
blood_volume = 400
|
||||
hunger_factor = 0.2
|
||||
|
||||
ambiguous_genders = TRUE
|
||||
|
||||
spawn_flags = SPECIES_CAN_JOIN | SPECIES_IS_WHITELISTED
|
||||
appearance_flags = HAS_HAIR_COLOR | HAS_SKIN_COLOR | HAS_EYE_COLOR
|
||||
bump_flag = MONKEY
|
||||
|
||||
@@ -162,6 +162,8 @@
|
||||
|
||||
darksight = 4
|
||||
|
||||
ambiguous_genders = TRUE
|
||||
|
||||
spawn_flags = SPECIES_CAN_JOIN | SPECIES_IS_WHITELISTED
|
||||
appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR
|
||||
|
||||
|
||||
@@ -895,6 +895,11 @@ var/global/list/damage_icon_parts = list()
|
||||
if(hud_used)
|
||||
hud_used.hidden_inventory_update() //Updates the screenloc of the items on the 'other' inventory bar
|
||||
|
||||
//update whether handcuffs appears on our hud.
|
||||
/mob/living/carbon/proc/update_hud_handcuffed()
|
||||
if(hud_used && hud_used.l_hand_hud_object && hud_used.r_hand_hud_object)
|
||||
hud_used.l_hand_hud_object.update_icon()
|
||||
hud_used.r_hand_hud_object.update_icon()
|
||||
|
||||
/mob/living/carbon/human/update_inv_handcuffed(var/update_icons=1)
|
||||
if(handcuffed)
|
||||
@@ -913,6 +918,8 @@ var/global/list/damage_icon_parts = list()
|
||||
|
||||
else
|
||||
overlays_standing[HANDCUFF_LAYER] = null
|
||||
|
||||
update_hud_handcuffed()
|
||||
if(update_icons) update_icons()
|
||||
|
||||
/mob/living/carbon/human/update_inv_legcuffed(var/update_icons=1)
|
||||
|
||||
@@ -545,97 +545,108 @@ var/list/ai_verbs_hidden = list( // For why this exists, refer to https://xkcd.c
|
||||
return
|
||||
|
||||
var/input
|
||||
if(alert("Would you like to select a hologram based on a crew member or switch to unique avatar?",,"Crew Member","Unique")=="Crew Member")
|
||||
var/choice = alert("Would you like to select a hologram based on a (visible) crew member, switch to unique avatar, or load your character from your character slot?",,"Crew Member","Unique","My Character")
|
||||
|
||||
var/personnel_list[] = list()
|
||||
switch(choice)
|
||||
if("Crew Member") //A seeable crew member (or a dog)
|
||||
var/list/targets = trackable_mobs()
|
||||
if(targets.len)
|
||||
input = input("Select a crew member:") as null|anything in targets //The definition of "crew member" is a little loose...
|
||||
//This is torture, I know. If someone knows a better way...
|
||||
if(!input) return
|
||||
var/new_holo = getHologramIcon(getCompoundIcon(targets[input]))
|
||||
qdel(holo_icon)
|
||||
holo_icon = new_holo
|
||||
|
||||
for(var/datum/data/record/t in data_core.locked)//Look in data core locked.
|
||||
personnel_list["[t.fields["name"]]: [t.fields["rank"]]"] = t.fields["image"]//Pull names, rank, and image.
|
||||
else
|
||||
alert("No suitable records found. Aborting.")
|
||||
|
||||
if(personnel_list.len)
|
||||
input = input("Select a crew member:") as null|anything in personnel_list
|
||||
var/icon/character_icon = personnel_list[input]
|
||||
if(character_icon)
|
||||
qdel(holo_icon)//Clear old icon so we're not storing it in memory.
|
||||
holo_icon = getHologramIcon(icon(character_icon))
|
||||
else
|
||||
alert("No suitable records found. Aborting.")
|
||||
if("My Character") //Loaded character slot
|
||||
if(!client || !client.prefs) return
|
||||
var/mob/living/carbon/human/dummy/dummy = new ()
|
||||
//This doesn't include custom_items because that's ... hard.
|
||||
client.prefs.dress_preview_mob(dummy)
|
||||
sleep(1 SECOND) //Strange bug in preview code? Without this, certain things won't show up. Yay race conditions?
|
||||
dummy.regenerate_icons()
|
||||
|
||||
else
|
||||
var/icon_list[] = list(
|
||||
"default",
|
||||
"floating face",
|
||||
"singularity",
|
||||
"drone",
|
||||
"carp",
|
||||
"spider",
|
||||
"bear",
|
||||
"slime",
|
||||
"ian",
|
||||
"runtime",
|
||||
"poly",
|
||||
"pun pun",
|
||||
"male human",
|
||||
"female human",
|
||||
"male unathi",
|
||||
"female unathi",
|
||||
"male tajara",
|
||||
"female tajara",
|
||||
"male tesharii",
|
||||
"female tesharii",
|
||||
"male skrell",
|
||||
"female skrell"
|
||||
)
|
||||
input = input("Please select a hologram:") as null|anything in icon_list
|
||||
if(input)
|
||||
var/new_holo = getHologramIcon(getCompoundIcon(dummy))
|
||||
qdel(holo_icon)
|
||||
switch(input)
|
||||
if("default")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo1"))
|
||||
if("floating face")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo2"))
|
||||
if("singularity")
|
||||
holo_icon = getHologramIcon(icon('icons/obj/singularity.dmi',"singularity_s1"))
|
||||
if("drone")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/animal.dmi',"drone0"))
|
||||
if("carp")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo4"))
|
||||
if("spider")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/animal.dmi',"nurse"))
|
||||
if("bear")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/animal.dmi',"brownbear"))
|
||||
if("slime")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/slimes.dmi',"cerulean adult slime"))
|
||||
if("ian")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/animal.dmi',"corgi"))
|
||||
if("runtime")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/animal.dmi',"cat"))
|
||||
if("poly")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/animal.dmi',"parrot_fly"))
|
||||
if("pun pun")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"punpun"))
|
||||
if("male human")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holohumm"))
|
||||
if("female human")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holohumf"))
|
||||
if("male unathi")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holounam"))
|
||||
if("female unathi")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holounaf"))
|
||||
if("male tajara")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holotajm"))
|
||||
if("female tajara")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holotajf"))
|
||||
if("male tesharii")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holotesm"))
|
||||
if("female tesharii")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holotesf"))
|
||||
if("male skrell")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holoskrm"))
|
||||
if("female skrell")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holoskrf"))
|
||||
qdel(dummy)
|
||||
holo_icon = new_holo
|
||||
|
||||
return
|
||||
else //A premade from the dmi
|
||||
var/icon_list[] = list(
|
||||
"default",
|
||||
"floating face",
|
||||
"singularity",
|
||||
"drone",
|
||||
"carp",
|
||||
"spider",
|
||||
"bear",
|
||||
"slime",
|
||||
"ian",
|
||||
"runtime",
|
||||
"poly",
|
||||
"pun pun",
|
||||
"male human",
|
||||
"female human",
|
||||
"male unathi",
|
||||
"female unathi",
|
||||
"male tajara",
|
||||
"female tajara",
|
||||
"male tesharii",
|
||||
"female tesharii",
|
||||
"male skrell",
|
||||
"female skrell"
|
||||
)
|
||||
input = input("Please select a hologram:") as null|anything in icon_list
|
||||
if(input)
|
||||
qdel(holo_icon)
|
||||
switch(input)
|
||||
if("default")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo1"))
|
||||
if("floating face")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo2"))
|
||||
if("singularity")
|
||||
holo_icon = getHologramIcon(icon('icons/obj/singularity.dmi',"singularity_s1"))
|
||||
if("drone")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/animal.dmi',"drone0"))
|
||||
if("carp")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo4"))
|
||||
if("spider")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/animal.dmi',"nurse"))
|
||||
if("bear")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/animal.dmi',"brownbear"))
|
||||
if("slime")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/slimes.dmi',"cerulean adult slime"))
|
||||
if("ian")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/animal.dmi',"corgi"))
|
||||
if("runtime")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/animal.dmi',"cat"))
|
||||
if("poly")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/animal.dmi',"parrot_fly"))
|
||||
if("pun pun")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"punpun"))
|
||||
if("male human")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holohumm"))
|
||||
if("female human")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holohumf"))
|
||||
if("male unathi")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holounam"))
|
||||
if("female unathi")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holounaf"))
|
||||
if("male tajara")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holotajm"))
|
||||
if("female tajara")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holotajf"))
|
||||
if("male tesharii")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holotesm"))
|
||||
if("female tesharii")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holotesf"))
|
||||
if("male skrell")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holoskrm"))
|
||||
if("female skrell")
|
||||
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holoskrf"))
|
||||
|
||||
//Toggles the luminosity and applies it by re-entereing the camera.
|
||||
/mob/living/silicon/ai/proc/toggle_camera_light()
|
||||
|
||||
@@ -689,7 +689,7 @@
|
||||
overlays += "eyes-[module_sprites[icontype]]"
|
||||
|
||||
if(opened)
|
||||
var/panelprefix = custom_sprite ? src.ckey : "ov"
|
||||
var/panelprefix = custom_sprite ? "[src.ckey]-[src.name]" : "ov"
|
||||
if(wiresexposed)
|
||||
overlays += "[panelprefix]-openpanel +w"
|
||||
else if(cell)
|
||||
|
||||
@@ -208,6 +208,7 @@ var/global/list/robot_modules = list(
|
||||
|
||||
/obj/item/weapon/robot_module/robot/medical/surgeon/New()
|
||||
..()
|
||||
src.modules += new /obj/item/borg/sight/hud/med(src)
|
||||
src.modules += new /obj/item/device/healthanalyzer(src)
|
||||
src.modules += new /obj/item/weapon/reagent_containers/borghypo(src)
|
||||
src.modules += new /obj/item/weapon/surgical/scalpel(src)
|
||||
|
||||
@@ -65,7 +65,13 @@
|
||||
src.take_organ_damage(0,20,emp=1)
|
||||
confused = (min(confused + 5, 30))
|
||||
if(2)
|
||||
src.take_organ_damage(0,15,emp=1)
|
||||
confused = (min(confused + 4, 30))
|
||||
if(3)
|
||||
src.take_organ_damage(0,10,emp=1)
|
||||
confused = (min(confused + 3, 30))
|
||||
if(4)
|
||||
src.take_organ_damage(0,5,emp=1)
|
||||
confused = (min(confused + 2, 30))
|
||||
flash_eyes(affect_silicon = 1)
|
||||
src << "<span class='danger'><B>*BZZZT*</B></span>"
|
||||
|
||||
+204
-172
@@ -1,172 +1,204 @@
|
||||
/mob/living/simple_animal/hostile/alien
|
||||
name = "alien hunter"
|
||||
desc = "Hiss!"
|
||||
icon = 'icons/mob/alien.dmi'
|
||||
icon_state = "alienh_running"
|
||||
icon_living = "alienh_running"
|
||||
icon_dead = "alien_l"
|
||||
icon_gib = "syndicate_gib"
|
||||
response_help = "pokes"
|
||||
response_disarm = "shoves"
|
||||
response_harm = "hits"
|
||||
speed = -1
|
||||
meat_type = /obj/item/weapon/reagent_containers/food/snacks/xenomeat
|
||||
maxHealth = 100
|
||||
health = 100
|
||||
harm_intent_damage = 5
|
||||
melee_damage_lower = 25
|
||||
melee_damage_upper = 25
|
||||
attacktext = "slashed"
|
||||
a_intent = I_HURT
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
min_oxy = 0
|
||||
max_oxy = 0
|
||||
min_tox = 0
|
||||
max_tox = 0
|
||||
min_co2 = 0
|
||||
max_co2 = 0
|
||||
min_n2 = 0
|
||||
max_n2 = 0
|
||||
unsuitable_atoms_damage = 15
|
||||
faction = "alien"
|
||||
environment_smash = 2
|
||||
status_flags = CANPUSH
|
||||
minbodytemp = 0
|
||||
heat_damage_per_tick = 20
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/alien/drone
|
||||
name = "alien drone"
|
||||
icon_state = "aliend_running"
|
||||
icon_living = "aliend_running"
|
||||
icon_dead = "aliend_l"
|
||||
health = 60
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 15
|
||||
|
||||
/mob/living/simple_animal/hostile/alien/sentinel
|
||||
name = "alien sentinel"
|
||||
icon_state = "aliens_running"
|
||||
icon_living = "aliens_running"
|
||||
icon_dead = "aliens_l"
|
||||
health = 120
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 15
|
||||
ranged = 1
|
||||
projectiletype = /obj/item/projectile/neurotox
|
||||
projectilesound = 'sound/weapons/pierce.ogg'
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/alien/queen
|
||||
name = "alien queen"
|
||||
icon_state = "alienq_running"
|
||||
icon_living = "alienq_running"
|
||||
icon_dead = "alienq_l"
|
||||
health = 250
|
||||
maxHealth = 250
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 15
|
||||
ranged = 1
|
||||
move_to_delay = 3
|
||||
projectiletype = /obj/item/projectile/neurotox
|
||||
projectilesound = 'sound/weapons/pierce.ogg'
|
||||
rapid = 1
|
||||
status_flags = 0
|
||||
|
||||
/mob/living/simple_animal/hostile/alien/queen/large
|
||||
name = "alien empress"
|
||||
icon = 'icons/mob/alienqueen.dmi'
|
||||
icon_state = "queen_s"
|
||||
icon_living = "queen_s"
|
||||
icon_dead = "queen_dead"
|
||||
move_to_delay = 4
|
||||
maxHealth = 400
|
||||
health = 400
|
||||
|
||||
/obj/item/projectile/neurotox
|
||||
damage = 30
|
||||
icon_state = "toxin"
|
||||
|
||||
/mob/living/simple_animal/hostile/alien/death()
|
||||
..()
|
||||
visible_message("[src] lets out a waning guttural screech, green blood bubbling from its maw...")
|
||||
playsound(src, 'sound/voice/hiss6.ogg', 100, 1)
|
||||
|
||||
// Xenoarch aliens.
|
||||
/mob/living/simple_animal/hostile/samak
|
||||
name = "samak"
|
||||
desc = "A fast, armoured predator accustomed to hiding and ambushing in cold terrain."
|
||||
faction = "samak"
|
||||
icon_state = "samak"
|
||||
icon_living = "samak"
|
||||
icon_dead = "samak_dead"
|
||||
icon = 'icons/jungle.dmi'
|
||||
move_to_delay = 2
|
||||
maxHealth = 125
|
||||
health = 125
|
||||
speed = 2
|
||||
melee_damage_lower = 5
|
||||
melee_damage_upper = 15
|
||||
attacktext = "mauled"
|
||||
cold_damage_per_tick = 0
|
||||
speak_chance = 5
|
||||
speak = list("Hruuugh!","Hrunnph")
|
||||
emote_see = list("paws the ground","shakes its mane","stomps")
|
||||
emote_hear = list("snuffles")
|
||||
|
||||
/mob/living/simple_animal/hostile/diyaab
|
||||
name = "diyaab"
|
||||
desc = "A small pack animal. Although omnivorous, it will hunt meat on occasion."
|
||||
faction = "diyaab"
|
||||
icon_state = "diyaab"
|
||||
icon_living = "diyaab"
|
||||
icon_dead = "diyaab_dead"
|
||||
icon = 'icons/jungle.dmi'
|
||||
move_to_delay = 1
|
||||
maxHealth = 25
|
||||
health = 25
|
||||
speed = 1
|
||||
melee_damage_lower = 1
|
||||
melee_damage_upper = 8
|
||||
attacktext = "gouged"
|
||||
cold_damage_per_tick = 0
|
||||
speak_chance = 5
|
||||
speak = list("Awrr?","Aowrl!","Worrl")
|
||||
emote_see = list("sniffs the air cautiously","looks around")
|
||||
emote_hear = list("snuffles")
|
||||
|
||||
/mob/living/simple_animal/hostile/shantak
|
||||
name = "shantak"
|
||||
desc = "A piglike creature with a bright iridiscent mane that sparkles as though lit by an inner light. Don't be fooled by its beauty though."
|
||||
faction = "shantak"
|
||||
icon_state = "shantak"
|
||||
icon_living = "shantak"
|
||||
icon_dead = "shantak_dead"
|
||||
icon = 'icons/jungle.dmi'
|
||||
move_to_delay = 1
|
||||
maxHealth = 75
|
||||
health = 75
|
||||
speed = 1
|
||||
melee_damage_lower = 3
|
||||
melee_damage_upper = 12
|
||||
attacktext = "gouged"
|
||||
cold_damage_per_tick = 0
|
||||
speak_chance = 5
|
||||
speak = list("Shuhn","Shrunnph?","Shunpf")
|
||||
emote_see = list("scratches the ground","shakes out it's mane","tinkles gently")
|
||||
|
||||
/mob/living/simple_animal/yithian
|
||||
name = "yithian"
|
||||
desc = "A friendly creature vaguely resembling an oversized snail without a shell."
|
||||
icon_state = "yithian"
|
||||
icon_living = "yithian"
|
||||
icon_dead = "yithian_dead"
|
||||
icon = 'icons/jungle.dmi'
|
||||
|
||||
/mob/living/simple_animal/tindalos
|
||||
name = "tindalos"
|
||||
desc = "It looks like a large, flightless grasshopper."
|
||||
icon_state = "tindalos"
|
||||
icon_living = "tindalos"
|
||||
icon_dead = "tindalos_dead"
|
||||
icon = 'icons/jungle.dmi'
|
||||
/mob/living/simple_animal/hostile/alien
|
||||
name = "alien hunter"
|
||||
desc = "Hiss!"
|
||||
icon = 'icons/mob/alien.dmi'
|
||||
icon_state = "alienh_running"
|
||||
icon_living = "alienh_running"
|
||||
icon_dead = "alien_l"
|
||||
icon_gib = "syndicate_gib"
|
||||
|
||||
faction = "xeno"
|
||||
cooperative = 1
|
||||
run_at_them = 0
|
||||
|
||||
response_help = "pokes"
|
||||
response_disarm = "shoves"
|
||||
response_harm = "hits"
|
||||
|
||||
maxHealth = 100
|
||||
health = 100
|
||||
speed = -1
|
||||
|
||||
harm_intent_damage = 5
|
||||
melee_damage_lower = 25
|
||||
melee_damage_upper = 25
|
||||
|
||||
attacktext = "slashed"
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
a_intent = I_HURT
|
||||
|
||||
environment_smash = 2
|
||||
status_flags = CANPUSH
|
||||
|
||||
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
|
||||
heat_damage_per_tick = 20
|
||||
unsuitable_atoms_damage = 15
|
||||
|
||||
meat_type = /obj/item/weapon/reagent_containers/food/snacks/xenomeat
|
||||
|
||||
/mob/living/simple_animal/hostile/alien/drone
|
||||
name = "alien drone"
|
||||
icon_state = "aliend_running"
|
||||
icon_living = "aliend_running"
|
||||
icon_dead = "aliend_l"
|
||||
health = 60
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 15
|
||||
|
||||
/mob/living/simple_animal/hostile/alien/sentinel
|
||||
name = "alien sentinel"
|
||||
icon_state = "aliens_running"
|
||||
icon_living = "aliens_running"
|
||||
icon_dead = "aliens_l"
|
||||
health = 120
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 15
|
||||
ranged = 1
|
||||
projectiletype = /obj/item/projectile/neurotox
|
||||
projectilesound = 'sound/weapons/pierce.ogg'
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/alien/queen
|
||||
name = "alien queen"
|
||||
icon_state = "alienq_running"
|
||||
icon_living = "alienq_running"
|
||||
icon_dead = "alienq_l"
|
||||
health = 250
|
||||
maxHealth = 250
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 15
|
||||
ranged = 1
|
||||
move_to_delay = 3
|
||||
projectiletype = /obj/item/projectile/neurotox
|
||||
projectilesound = 'sound/weapons/pierce.ogg'
|
||||
rapid = 1
|
||||
status_flags = 0
|
||||
|
||||
/mob/living/simple_animal/hostile/alien/queen/large
|
||||
name = "alien empress"
|
||||
icon = 'icons/mob/alienqueen.dmi'
|
||||
icon_state = "queen_s"
|
||||
icon_living = "queen_s"
|
||||
icon_dead = "queen_dead"
|
||||
move_to_delay = 4
|
||||
maxHealth = 400
|
||||
health = 400
|
||||
|
||||
/obj/item/projectile/neurotox
|
||||
damage = 30
|
||||
icon_state = "toxin"
|
||||
|
||||
/mob/living/simple_animal/hostile/alien/death()
|
||||
..()
|
||||
visible_message("[src] lets out a waning guttural screech, green blood bubbling from its maw...")
|
||||
playsound(src, 'sound/voice/hiss6.ogg', 100, 1)
|
||||
|
||||
// Xenoarch aliens.
|
||||
/mob/living/simple_animal/hostile/samak
|
||||
name = "samak"
|
||||
desc = "A fast, armoured predator accustomed to hiding and ambushing in cold terrain."
|
||||
faction = "samak"
|
||||
icon_state = "samak"
|
||||
icon_living = "samak"
|
||||
icon_dead = "samak_dead"
|
||||
icon = 'icons/jungle.dmi'
|
||||
|
||||
faction = "samak"
|
||||
|
||||
maxHealth = 125
|
||||
health = 125
|
||||
speed = 2
|
||||
move_to_delay = 2
|
||||
|
||||
melee_damage_lower = 5
|
||||
melee_damage_upper = 15
|
||||
|
||||
attacktext = "mauled"
|
||||
cold_damage_per_tick = 0
|
||||
|
||||
speak_chance = 5
|
||||
speak = list("Hruuugh!","Hrunnph")
|
||||
emote_see = list("paws the ground","shakes its mane","stomps")
|
||||
emote_hear = list("snuffles")
|
||||
|
||||
/mob/living/simple_animal/hostile/diyaab
|
||||
name = "diyaab"
|
||||
desc = "A small pack animal. Although omnivorous, it will hunt meat on occasion."
|
||||
faction = "diyaab"
|
||||
icon_state = "diyaab"
|
||||
icon_living = "diyaab"
|
||||
icon_dead = "diyaab_dead"
|
||||
icon = 'icons/jungle.dmi'
|
||||
|
||||
faction = "diyaab"
|
||||
cooperative = 1
|
||||
|
||||
maxHealth = 25
|
||||
health = 25
|
||||
speed = 1
|
||||
move_to_delay = 1
|
||||
|
||||
melee_damage_lower = 1
|
||||
melee_damage_upper = 8
|
||||
|
||||
attacktext = "gouged"
|
||||
cold_damage_per_tick = 0
|
||||
|
||||
speak_chance = 5
|
||||
speak = list("Awrr?","Aowrl!","Worrl")
|
||||
emote_see = list("sniffs the air cautiously","looks around")
|
||||
emote_hear = list("snuffles")
|
||||
|
||||
/mob/living/simple_animal/hostile/shantak
|
||||
name = "shantak"
|
||||
desc = "A piglike creature with a bright iridiscent mane that sparkles as though lit by an inner light. Don't be fooled by its beauty though."
|
||||
faction = "shantak"
|
||||
icon_state = "shantak"
|
||||
icon_living = "shantak"
|
||||
icon_dead = "shantak_dead"
|
||||
icon = 'icons/jungle.dmi'
|
||||
|
||||
faction = "shantak"
|
||||
|
||||
maxHealth = 75
|
||||
health = 75
|
||||
speed = 1
|
||||
move_to_delay = 1
|
||||
|
||||
melee_damage_lower = 3
|
||||
melee_damage_upper = 12
|
||||
|
||||
attacktext = "gouged"
|
||||
cold_damage_per_tick = 0
|
||||
|
||||
speak_chance = 5
|
||||
speak = list("Shuhn","Shrunnph?","Shunpf")
|
||||
emote_see = list("scratches the ground","shakes out it's mane","tinkles gently")
|
||||
|
||||
/mob/living/simple_animal/yithian
|
||||
name = "yithian"
|
||||
desc = "A friendly creature vaguely resembling an oversized snail without a shell."
|
||||
icon_state = "yithian"
|
||||
icon_living = "yithian"
|
||||
icon_dead = "yithian_dead"
|
||||
icon = 'icons/jungle.dmi'
|
||||
|
||||
faction = "yithian"
|
||||
|
||||
/mob/living/simple_animal/tindalos
|
||||
name = "tindalos"
|
||||
desc = "It looks like a large, flightless grasshopper."
|
||||
icon_state = "tindalos"
|
||||
icon_living = "tindalos"
|
||||
icon_dead = "tindalos_dead"
|
||||
icon = 'icons/jungle.dmi'
|
||||
|
||||
faction = "tindalos"
|
||||
+73
-72
@@ -1,72 +1,73 @@
|
||||
/mob/living/simple_animal/hostile/creature
|
||||
name = "creature"
|
||||
desc = "A sanity-destroying otherthing."
|
||||
icon = 'icons/mob/critter.dmi'
|
||||
speak_emote = list("gibbers")
|
||||
icon_state = "otherthing"
|
||||
icon_living = "otherthing"
|
||||
icon_dead = "otherthing-dead"
|
||||
maxHealth = 40
|
||||
health = 40
|
||||
|
||||
harm_intent_damage = 8
|
||||
melee_damage_lower = 5
|
||||
melee_damage_upper = 5
|
||||
attacktext = "chomped"
|
||||
attack_sound = 'sound/weapons/bite.ogg'
|
||||
faction = "creature"
|
||||
speed = 8
|
||||
|
||||
/mob/living/simple_animal/hostile/creature/cult
|
||||
faction = "cult"
|
||||
|
||||
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
|
||||
|
||||
supernatural = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/creature/cult/cultify()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/creature/cult/Life()
|
||||
..()
|
||||
check_horde()
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/creature/strong
|
||||
maxHealth = 160
|
||||
health = 160
|
||||
|
||||
harm_intent_damage = 5
|
||||
melee_damage_lower = 8
|
||||
melee_damage_upper = 25
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/creature/strong/cult
|
||||
faction = "cult"
|
||||
|
||||
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
|
||||
|
||||
supernatural = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/creature/cult/cultify()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/creature/cult/Life()
|
||||
..()
|
||||
check_horde()
|
||||
/mob/living/simple_animal/hostile/creature
|
||||
name = "creature"
|
||||
desc = "A sanity-destroying otherthing."
|
||||
icon = 'icons/mob/critter.dmi'
|
||||
icon_state = "otherthing"
|
||||
icon_living = "otherthing"
|
||||
icon_dead = "otherthing-dead"
|
||||
|
||||
faction = "creature"
|
||||
maxHealth = 40
|
||||
health = 40
|
||||
speed = 8
|
||||
|
||||
harm_intent_damage = 8
|
||||
melee_damage_lower = 5
|
||||
melee_damage_upper = 5
|
||||
|
||||
attacktext = "chomped"
|
||||
attack_sound = 'sound/weapons/bite.ogg'
|
||||
|
||||
speak_emote = list("gibbers")
|
||||
|
||||
/mob/living/simple_animal/hostile/creature/cult
|
||||
faction = "cult"
|
||||
|
||||
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
|
||||
|
||||
supernatural = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/creature/cult/cultify()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/creature/cult/Life()
|
||||
..()
|
||||
check_horde()
|
||||
|
||||
/mob/living/simple_animal/hostile/creature/strong
|
||||
maxHealth = 160
|
||||
health = 160
|
||||
|
||||
harm_intent_damage = 5
|
||||
melee_damage_lower = 8
|
||||
melee_damage_upper = 25
|
||||
|
||||
/mob/living/simple_animal/hostile/creature/strong/cult
|
||||
faction = "cult"
|
||||
|
||||
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
|
||||
|
||||
supernatural = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/creature/cult/cultify()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/creature/cult/Life()
|
||||
..()
|
||||
check_horde()
|
||||
+33
-40
@@ -1,39 +1,29 @@
|
||||
|
||||
//malfunctioning combat drones
|
||||
/mob/living/simple_animal/hostile/retaliate/malf_drone
|
||||
/mob/living/simple_animal/hostile/malf_drone
|
||||
name = "combat drone"
|
||||
desc = "An automated combat drone armed with state of the art weaponry and shielding."
|
||||
icon_state = "drone3"
|
||||
icon_living = "drone3"
|
||||
icon_dead = "drone_dead"
|
||||
ranged = 1
|
||||
rapid = 1
|
||||
speak_chance = 5
|
||||
|
||||
faction = "malf_drone"
|
||||
maxHealth = 300
|
||||
health = 300
|
||||
speed = 8
|
||||
stop_when_pulled = 0
|
||||
|
||||
turns_per_move = 3
|
||||
response_help = "pokes"
|
||||
response_disarm = "gently pushes aside"
|
||||
response_harm = "hits"
|
||||
speak = list("ALERT.","Hostile-ile-ile entities dee-twhoooo-wected.","Threat parameterszzzz- szzet.","Bring sub-sub-sub-systems uuuup to combat alert alpha-a-a.")
|
||||
emote_see = list("beeps menacingly","whirrs threateningly","scans its immediate vicinity")
|
||||
|
||||
a_intent = I_HURT
|
||||
stop_automated_movement_when_pulled = 0
|
||||
health = 300
|
||||
maxHealth = 300
|
||||
speed = 8
|
||||
ranged = 1
|
||||
rapid = 1
|
||||
projectiletype = /obj/item/projectile/beam/drone
|
||||
projectilesound = 'sound/weapons/laser3.ogg'
|
||||
destroy_surroundings = 0
|
||||
var/datum/effect/effect/system/ion_trail_follow/ion_trail
|
||||
|
||||
//the drone randomly switches between these states because it's malfunctioning
|
||||
var/hostile_drone = 0
|
||||
//0 - retaliate, only attack enemies that attack it
|
||||
//1 - hostile, attack everything that comes near
|
||||
|
||||
var/turf/patrol_target
|
||||
var/explode_chance = 1
|
||||
var/disabled = 0
|
||||
var/exploding = 0
|
||||
|
||||
//Drones aren't affected by atmos.
|
||||
min_oxy = 0
|
||||
@@ -46,10 +36,19 @@
|
||||
max_n2 = 0
|
||||
minbodytemp = 0
|
||||
|
||||
var/has_loot = 1
|
||||
faction = "malf_drone"
|
||||
speak_chance = 5
|
||||
speak = list("ALERT.","Hostile-ile-ile entities dee-twhoooo-wected.","Threat parameterszzzz- szzet.","Bring sub-sub-sub-systems uuuup to combat alert alpha-a-a.")
|
||||
emote_see = list("beeps menacingly","whirrs threateningly","scans its immediate vicinity")
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/malf_drone/New()
|
||||
|
||||
var/datum/effect/effect/system/ion_trail_follow/ion_trail
|
||||
var/turf/patrol_target
|
||||
var/explode_chance = 1
|
||||
var/disabled = 0
|
||||
var/exploding = 0
|
||||
var/has_loot = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/malf_drone/New()
|
||||
..()
|
||||
if(prob(5))
|
||||
projectiletype = /obj/item/projectile/beam/pulse/drone
|
||||
@@ -58,17 +57,11 @@
|
||||
ion_trail.set_up(src)
|
||||
ion_trail.start()
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/malf_drone/Process_Spacemove(var/check_drift = 0)
|
||||
/mob/living/simple_animal/malf_drone/Process_Spacemove(var/check_drift = 0)
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/malf_drone/ListTargets()
|
||||
if(hostile_drone)
|
||||
return view(src, 10)
|
||||
else
|
||||
return ..()
|
||||
|
||||
//self repair systems have a chance to bring the drone back to life
|
||||
/mob/living/simple_animal/hostile/retaliate/malf_drone/Life()
|
||||
/mob/living/simple_animal/hostile/malf_drone/Life()
|
||||
|
||||
//emps and lots of damage can temporarily shut us down
|
||||
if(disabled > 0)
|
||||
@@ -99,12 +92,12 @@
|
||||
|
||||
//sometimes our targetting sensors malfunction, and we attack anyone nearby
|
||||
if(prob(disabled ? 0 : 1))
|
||||
if(hostile_drone)
|
||||
if(hostile)
|
||||
src.visible_message("\blue \icon[src] [src] retracts several targetting vanes, and dulls it's running lights.")
|
||||
hostile_drone = 0
|
||||
hostile = 0
|
||||
else
|
||||
src.visible_message("\red \icon[src] [src] suddenly lights up, and additional targetting vanes slide into place.")
|
||||
hostile_drone = 1
|
||||
hostile = 1
|
||||
|
||||
if(health / maxHealth > 0.9)
|
||||
icon_state = "drone3"
|
||||
@@ -151,18 +144,18 @@
|
||||
..()
|
||||
|
||||
//ion rifle!
|
||||
/mob/living/simple_animal/hostile/retaliate/malf_drone/emp_act(severity)
|
||||
/mob/living/simple_animal/hostile/malf_drone/emp_act(severity)
|
||||
health -= rand(3,15) * (severity + 1)
|
||||
disabled = rand(150, 600)
|
||||
hostile_drone = 0
|
||||
hostile = 0
|
||||
walk(src,0)
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/malf_drone/death()
|
||||
/mob/living/simple_animal/hostile/malf_drone/death()
|
||||
..(null,"suddenly breaks apart.")
|
||||
qdel(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/retaliate/malf_drone/Destroy()
|
||||
//some random debris left behind
|
||||
/mob/living/simple_animal/hostile/malf_drone/Destroy()
|
||||
//More advanced than the default S_A loot system, for visual effect and random tech levels.
|
||||
if(has_loot)
|
||||
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
|
||||
s.set_up(3, 1, src)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user