"
+ dat += "Issuing ID: [giver] "
+ dat += "Issued to: [giv_name] "
+ dat += "Reason: [reason] "
+ dat += "Duration (minutes): [duration] m "
+ dat += "Access to areas: "
+ if (giver && giver.access)
+ for (var/A in giver.access)
+ var/area = get_access_desc(A)
+ if (A in accesses)
+ area = "[area]"
+ dat += "[area] "
+ dat += " Issue pass "
+
+ user << browse(dat, "window=guestpass;size=400x520")
+ onclose(user, "guestpass")
+
+
+/obj/machinery/computer/guestpass/Topic(href, href_list)
+ if(..())
+ return
+ usr.set_machine(src)
+ if (href_list["mode"])
+ mode = text2num(href_list["mode"])
+
+ if (href_list["choice"])
+ switch(href_list["choice"])
+ if ("giv_name")
+ var/nam = input("Person pass is issued to", "Name", name)
+ if (nam)
+ giv_name = nam
+ if ("reason")
+ var/reas = input("Reason why pass is issued", "Reason", reason)
+ reason = reas
+ if ("duration")
+ var/dur = input("Duration (in minutes) during which pass is valid.", "Duration") as num
+ if (dur > 0 && dur < 30)
+ duration = dur
+ else
+ usr << "\red Invalid duration."
+ if ("access")
+ var/A = text2num(href_list["access"])
+ if (A in accesses)
+ accesses.Remove(A)
+ else
+ accesses.Add(A)
+ if (href_list["action"])
+ switch(href_list["action"])
+ if ("id")
+ if (giver)
+ if(ishuman(usr))
+ giver.loc = usr.loc
+ if(!usr.get_active_hand())
+ usr.put_in_hands(giver)
+ giver = null
+ else
+ giver.loc = src.loc
+ giver = null
+ else
+ var/obj/item/I = usr.get_active_hand()
+ if (istype(I, /obj/item/weapon/card/id))
+ usr.drop_item()
+ I.loc = src
+ giver = I
+ updateUsrDialog()
+
+ if ("print")
+ var/dat = "
Activity log of guest pass terminal #[uid]
"
+ for (var/entry in internal_log)
+ dat += "[entry] "
+ //usr << "Printing the log, standby..."
+ //sleep(50)
+ var/obj/item/weapon/paper/P = new/obj/item/weapon/paper( loc )
+ P.name = "activity log"
+ P.info = dat
+
+ if ("issue")
+ if (giver)
+ var/number = add_zero("[rand(0,9999)]", 4)
+ var/entry = "\[[worldtime2text()]\] Pass #[number] issued by [giver.registered_name] ([giver.assignment]) to [giv_name]. Reason: [reason]. Grants access to following areas: "
+ for (var/i=1 to accesses.len)
+ var/A = accesses[i]
+ if (A)
+ var/area = get_access_desc(A)
+ entry += "[i > 1 ? ", [area]" : "[area]"]"
+ entry += ". Expires at [worldtime2text(world.time + duration*10*60)]."
+ internal_log.Add(entry)
+
+ var/obj/item/weapon/card/id/guest/pass = new(src.loc)
+ pass.temp_access = accesses.Copy()
+ pass.registered_name = giv_name
+ pass.expiration_time = world.time + duration*10*60
+ pass.reason = reason
+ pass.name = "guest pass #[number]"
+ else
+ usr << "\red Cannot issue pass without issuing ID."
+ updateUsrDialog()
+ return
\ No newline at end of file
diff --git a/code/WorkInProgress/Cib/MedicalSideEffects.dm b/code/WorkInProgress/Cib/MedicalSideEffects.dm
index 15580c4bd2e..62f9cf75f80 100644
--- a/code/WorkInProgress/Cib/MedicalSideEffects.dm
+++ b/code/WorkInProgress/Cib/MedicalSideEffects.dm
@@ -83,7 +83,7 @@
/datum/medical_effect/headache
name = "Headache"
triggers = list("cryoxadone" = 10, "bicaridine" = 15, "tricordrazine" = 15)
- cures = list("alkysine", "tramadol")
+ cures = list("alkysine", "tramadol", "paracetamol", "oxycodone")
cure_message = "Your head stops throbbing..."
/datum/medical_effect/headache/on_life(mob/living/carbon/human/H, strength)
diff --git a/code/WorkInProgress/Cib/amorph/life.dm b/code/WorkInProgress/Cib/amorph/life.dm
index 14c4d41ccab..e23662bbbba 100644
--- a/code/WorkInProgress/Cib/amorph/life.dm
+++ b/code/WorkInProgress/Cib/amorph/life.dm
@@ -148,7 +148,7 @@
if(!block)
- for(var/obj/effect/effect/chem_smoke/smoke in view(1, src))
+ for(var/obj/effect/effect/smoke/chem/smoke in view(1, src))
if(smoke.reagents.total_volume)
smoke.reagents.reaction(src, INGEST)
spawn(5)
diff --git a/code/WorkInProgress/Yinadele/Supermatter.dm b/code/WorkInProgress/Yinadele/Supermatter.dm
new file mode 100644
index 00000000000..7765393bb1d
--- /dev/null
+++ b/code/WorkInProgress/Yinadele/Supermatter.dm
@@ -0,0 +1,265 @@
+
+#define NITROGEN_RETARDATION_FACTOR 4 //Higher == N2 slows reaction more
+#define THERMAL_RELEASE_MODIFIER 10 //Higher == less heat released during reaction
+#define PLASMA_RELEASE_MODIFIER 1500 //Higher == less plasma released by reaction
+#define OXYGEN_RELEASE_MODIFIER 750 //Higher == less oxygen released at high temperature/power
+#define REACTION_POWER_MODIFIER 1.1 //Higher == more overall power
+
+
+//These would be what you would get at point blank, decreases with distance
+#define DETONATION_RADS 200
+#define DETONATION_HALLUCINATION 600
+
+
+#define WARNING_DELAY 60 //45 seconds between warnings.
+
+/obj/machinery/power/supermatter
+ name = "Supermatter"
+ desc = "A strangely translucent and iridescent crystal. \red You get headaches just from looking at it."
+ icon = 'icons/obj/engine.dmi'
+ icon_state = "darkmatter"
+ density = 1
+ anchored = 0
+
+ var/gasefficency = 0.25
+
+ var/base_icon_state = "darkmatter"
+
+ var/damage = 0
+ var/damage_archived = 0
+ var/safe_alert = "Crystaline hyperstructure returning to safe operating levels."
+ var/warning_point = 100
+ var/warning_alert = "Danger! Crystal hyperstructure instability!"
+ var/emergency_point = 700
+ var/emergency_alert = "CRYSTAL DELAMINATION IMMINENT."
+ var/explosion_point = 1000
+
+ var/emergency_issued = 0
+
+ var/explosion_power = 8
+
+ var/lastwarning = 0 // Time in 1/10th of seconds since the last sent warning
+
+ var/power = 0
+
+ //Temporary values so that we can optimize this
+ //How much the bullets damage should be multiplied by when it is added to the internal variables
+ var/config_bullet_energy = 2
+ //How much of the power is left after processing is finished?
+// var/config_power_reduction_per_tick = 0.5
+ //How much hallucination should it produce per unit of power?
+ var/config_hallucination_power = 0.1
+
+ var/obj/item/device/radio/radio
+
+ shard //Small subtype, less efficient and more sensitive, but less boom.
+ name = "Supermatter Shard"
+ desc = "A strangely translucent and iridescent crystal that looks like it used to be part of a larger structure. \red You get headaches just from looking at it."
+ icon_state = "darkmatter_shard"
+ base_icon_state = "darkmatter_shard"
+
+ warning_point = 50
+ emergency_point = 500
+ explosion_point = 900
+
+ gasefficency = 0.125
+
+ explosion_power = 3 //3,6,9,12? Or is that too small?
+
+
+/obj/machinery/power/supermatter/New()
+ . = ..()
+ radio = new (src)
+
+
+/obj/machinery/power/supermatter/Del()
+ del radio
+ . = ..()
+
+/obj/machinery/power/supermatter/proc/explode()
+ explosion(get_turf(src), explosion_power, explosion_power * 2, explosion_power * 3, explosion_power * 4, 1)
+ del src
+ return
+
+/obj/machinery/power/supermatter/process()
+
+ var/turf/L = loc
+
+ if(isnull(L)) // We have a null turf...something is wrong, stop processing this entity.
+ return PROCESS_KILL
+
+ if(!istype(L)) //We are in a crate or somewhere that isn't turf, if we return to turf resume processing but for now.
+ return //Yeah just stop.
+
+ if(damage > warning_point) // while the core is still damaged and it's still worth noting its status
+ if((world.timeofday - lastwarning) / 10 >= WARNING_DELAY)
+
+ if(damage > emergency_point)
+ radio.autosay(emergency_alert, "Supermatter Monitor")
+ lastwarning = world.timeofday
+
+ else if(damage >= damage_archived) // The damage is still going up
+ radio.autosay(warning_alert, "Supermatter Monitor")
+ lastwarning = world.timeofday - 150
+
+ else // Phew, we're safe
+ radio.autosay(safe_alert, "Supermatter Monitor")
+ lastwarning = world.timeofday
+
+ if(damage > explosion_point)
+ for(var/mob/living/mob in living_mob_list)
+ if(istype(mob, /mob/living/carbon/human))
+ //Hilariously enough, running into a closet should make you get hit the hardest.
+ mob:hallucination += max(50, min(300, DETONATION_HALLUCINATION * sqrt(1 / (get_dist(mob, src) + 1)) ) )
+ var/rads = DETONATION_RADS * sqrt( 1 / (get_dist(mob, src) + 1) )
+ mob.apply_effect(rads, IRRADIATE)
+
+ explode()
+
+ //Ok, get the air from the turf
+ var/datum/gas_mixture/env = L.return_air()
+
+ //Remove gas from surrounding area
+ var/datum/gas_mixture/removed = env.remove(gasefficency * env.total_moles)
+
+ if(!removed || !removed.total_moles)
+ damage += max((power-1600)/10, 0)
+ power = min(power, 1600)
+ return 1
+
+ if (!removed)
+ return 1
+
+ damage_archived = damage
+ damage = max( damage + ( (removed.temperature - 800) / 150 ) , 0 )
+ //Ok, 100% oxygen atmosphere = best reaction
+ //Maxes out at 100% oxygen pressure
+ var/oxygen = max(min((removed.oxygen - (removed.nitrogen * NITROGEN_RETARDATION_FACTOR)) / MOLES_CELLSTANDARD, 1), 0)
+
+ var/temp_factor = 100
+
+ if(oxygen > 0.8)
+ // with a perfect gas mix, make the power less based on heat
+ icon_state = "[base_icon_state]_glow"
+ else
+ // in normal mode, base the produced energy around the heat
+ temp_factor = 60
+ icon_state = base_icon_state
+
+ power = max( (removed.temperature * temp_factor / T0C) * oxygen + power, 0) //Total laser power plus an overload
+
+ //We've generated power, now let's transfer it to the collectors for storing/usage
+ transfer_energy()
+
+ var/device_energy = power * REACTION_POWER_MODIFIER
+
+ //To figure out how much temperature to add each tick, consider that at one atmosphere's worth
+ //of pure oxygen, with all four lasers firing at standard energy and no N2 present, at room temperature
+ //that the device energy is around 2140. At that stage, we don't want too much heat to be put out
+ //Since the core is effectively "cold"
+
+ //Also keep in mind we are only adding this temperature to (efficiency)% of the one tile the rock
+ //is on. An increase of 4*C @ 25% efficiency here results in an increase of 1*C / (#tilesincore) overall.
+ removed.temperature += (device_energy / THERMAL_RELEASE_MODIFIER)
+
+ removed.temperature = max(0, min(removed.temperature, 2500))
+
+ //Calculate how much gas to release
+ removed.toxins += max(device_energy / PLASMA_RELEASE_MODIFIER, 0)
+
+ removed.oxygen += max((device_energy + removed.temperature - T0C) / OXYGEN_RELEASE_MODIFIER, 0)
+
+ removed.update_values()
+
+ env.merge(removed)
+
+ for(var/mob/living/carbon/human/l in view(src, round(power ** 0.25))) // you have to be seeing the core to get hallucinations
+ if(!istype(l.glasses, /obj/item/clothing/glasses/meson))
+ l.hallucination = max(0, min(200, l.hallucination + power * config_hallucination_power * sqrt( 1 / max(1,get_dist(l, src)) ) ) )
+
+ for(var/mob/living/l in range(src, round((power / 100) ** 0.25)))
+ var/rads = (power / 10) * sqrt( 1 / get_dist(l, src) )
+ l.apply_effect(rads, IRRADIATE)
+
+ power -= (power/500)**3
+
+ return 1
+
+
+/obj/machinery/power/supermatter/bullet_act(var/obj/item/projectile/Proj)
+ if(Proj.flag != "bullet")
+ power += Proj.damage * config_bullet_energy
+ else
+ damage += Proj.damage * config_bullet_energy
+ return 0
+
+
+/obj/machinery/power/supermatter/attack_paw(mob/user as mob)
+ return attack_hand(user)
+
+
+/obj/machinery/power/supermatter/attack_robot(mob/user as mob)
+ if(Adjacent(user))
+ return attack_hand(user)
+ else
+ user << "You attempt to interface with the control circuits but find they are not connected to your network. Maybe in a future firmware update."
+ return
+
+/obj/machinery/power/supermatter/attack_ai(mob/user as mob)
+ user << "You attempt to interface with the control circuits but find they are not connected to your network. Maybe in a future firmware update."
+
+/obj/machinery/power/supermatter/attack_hand(mob/user as mob)
+ user.visible_message("\The [user] reaches out and touches \the [src], inducing a resonance... \his body starts to glow and bursts into flames before flashing into ash.",\
+ "You reach out and touch \the [src]. Everything starts burning and all you can hear is ringing. Your last thought is \"That was not a wise decision.\"",\
+ "You hear an uneartly ringing, then what sounds like a shrilling kettle as you are washed with a wave of heat.")
+
+ Consume(user)
+
+/obj/machinery/power/supermatter/proc/transfer_energy()
+ for(var/obj/machinery/power/rad_collector/R in rad_collectors)
+ if(get_dist(R, src) <= 15) // Better than using orange() every process
+ R.receive_pulse(power)
+ return
+
+/obj/machinery/power/supermatter/attackby(obj/item/weapon/W as obj, mob/living/user as mob)
+ user.visible_message("\The [user] touches \a [W] to \the [src] as a silence fills the room...",\
+ "You touch \the [W] to \the [src] when everything suddenly goes silent.\"\n\The [W] flashes into dust as you flinch away from \the [src].",\
+ "Everything suddenly goes silent.")
+
+ user.drop_from_inventory(W)
+ Consume(W)
+
+ user.apply_effect(150, IRRADIATE)
+
+
+/obj/machinery/power/supermatter/Bumped(atom/AM as mob|obj)
+ if(istype(AM, /mob/living))
+ AM.visible_message("\The [AM] slams into \the [src] inducing a resonance... \his body starts to glow and catch flame before flashing into ash.",\
+ "You slam into \the [src] as your ears are filled with unearthly ringing. Your last thought is \"Oh, fuck.\"",\
+ "You hear an uneartly ringing, then what sounds like a shrilling kettle as you are washed with a wave of heat.")
+ else
+ AM.visible_message("\The [AM] smacks into \the [src] and rapidly flashes to ash.",\
+ "You hear a loud crack as you are washed with a wave of heat.")
+
+ Consume(AM)
+
+
+/obj/machinery/power/supermatter/proc/Consume(var/mob/living/user)
+ if(istype(user))
+ user.dust()
+ power += 200
+ else
+ del user
+
+ power += 200
+
+ //Some poor sod got eaten, go ahead and irradiate people nearby.
+ for(var/mob/living/l in range(10))
+ if(l in view())
+ l.show_message("As \the [src] slowly stops resonating, you find your skin covered in new radiation burns.", 1,\
+ "The unearthly ringing subsides and you notice you have new radiation burns.", 2)
+ else
+ l.show_message("You hear an uneartly ringing and notice your skin is covered in fresh radiation burns.", 2)
+ var/rads = 500 * sqrt( 1 / (get_dist(l, src) + 1) )
+ l.apply_effect(rads, IRRADIATE)
+
diff --git a/code/WorkInProgress/buildmode.dm b/code/WorkInProgress/buildmode.dm
index 28beed7f049..ceb1954a5d8 100644
--- a/code/WorkInProgress/buildmode.dm
+++ b/code/WorkInProgress/buildmode.dm
@@ -120,7 +120,7 @@
screen_loc = "NORTH,WEST+2"
var/varholder = "name"
var/valueholder = "derp"
- var/objholder = "/obj/structure/closet"
+ var/objholder = /obj/structure/closet
Click(location, control, params)
var/list/pa = params2list(params)
@@ -145,13 +145,13 @@
if(1)
return 1
if(2)
- objholder = input(usr,"Enter typepath:" ,"Typepath","/obj/structure/closet")
- var/list/removed_paths = list("/obj/effect/bhole")
- if(objholder in removed_paths)
+ objholder = text2path(input(usr,"Enter typepath:" ,"Typepath","/obj/structure/closet"))
+ if(!ispath(objholder))
+ objholder = /obj/structure/closet
alert("That path is not allowed.")
- objholder = "/obj/structure/closet"
- else if (dd_hasprefix(objholder, "/mob") && !check_rights(R_DEBUG,0))
- objholder = "/obj/structure/closet"
+ else
+ if(ispath(objholder,/mob) && !check_rights(R_DEBUG,0))
+ objholder = /obj/structure/closet
if(3)
var/list/locked = list("vars", "key", "ckey", "client", "firemut", "ishulk", "telekinesis", "xray", "virus", "viruses", "cuffed", "ka", "last_eaten", "urine")
@@ -234,8 +234,12 @@
WIN.dir = NORTHWEST
if(2)
if(pa.Find("left"))
- var/obj/A = new holder.buildmode.objholder (get_turf(object))
- A.dir = holder.builddir.dir
+ if(ispath(holder.buildmode.objholder,/turf))
+ var/turf/T = get_turf(object)
+ T.ChangeTurf(holder.buildmode.objholder)
+ else
+ var/obj/A = new holder.buildmode.objholder (get_turf(object))
+ A.dir = holder.builddir.dir
else if(pa.Find("right"))
if(isobj(object)) del(object)
diff --git a/code/WorkInProgress/carn/master_controller_semi-seq.dm b/code/WorkInProgress/carn/master_controller_semi-seq.dm
index 96e7eacda6e..0f9b4f666d9 100644
--- a/code/WorkInProgress/carn/master_controller_semi-seq.dm
+++ b/code/WorkInProgress/carn/master_controller_semi-seq.dm
@@ -50,7 +50,7 @@ datum/controller/game_controller/New()
if(!syndicate_code_response) syndicate_code_response = generate_code_phrase()
if(!ticker) ticker = new /datum/controller/gameticker()
if(!emergency_shuttle) emergency_shuttle = new /datum/shuttle_controller/emergency_shuttle()
-
+ if(artifact_spawn) artifact_spawning_turfs = artifact_spawn
datum/controller/game_controller/proc/setup()
world.tick_lag = config.Ticklag
diff --git a/code/WorkInProgress/explosion_particles.dm b/code/WorkInProgress/explosion_particles.dm
index 11e2cc4f01f..90020e50801 100644
--- a/code/WorkInProgress/explosion_particles.dm
+++ b/code/WorkInProgress/explosion_particles.dm
@@ -65,6 +65,6 @@
P.set_up(10,location)
P.start()
spawn(5)
- var/datum/effect/effect/system/harmless_smoke_spread/S = new/datum/effect/effect/system/harmless_smoke_spread()
+ var/datum/effect/effect/system/smoke_spread/S = new/datum/effect/effect/system/smoke_spread()
S.set_up(5,0,location,null)
S.start()
\ No newline at end of file
diff --git a/code/WorkInProgress/kilakk/fax.dm b/code/WorkInProgress/kilakk/fax.dm
index 7ab0440a6bc..0d8f4cdde1f 100644
--- a/code/WorkInProgress/kilakk/fax.dm
+++ b/code/WorkInProgress/kilakk/fax.dm
@@ -1,19 +1,35 @@
+var/list/obj/machinery/faxmachine/allfaxes = list()
+var/list/alldepartments = list("Central Command")
+
/obj/machinery/faxmachine
name = "fax machine"
icon = 'icons/obj/library.dmi'
icon_state = "fax"
- req_access = list(access_lawyer)
+ req_one_access = list(access_lawyer, access_heads)
anchored = 1
density = 1
use_power = 1
idle_power_usage = 30
active_power_usage = 200
power_channel = EQUIP
+
var/obj/item/weapon/card/id/scan = null // identification
var/authenticated = 0
- var/obj/item/weapon/paper/tofax = null // what we're sending to central
+
+ var/obj/item/weapon/paper/tofax = null // what we're sending
var/sendcooldown = 0 // to avoid spamming fax messages
+ var/department = "Unknown" // our department
+
+ var/dpt = "Central Command" // the department we're sending to
+
+/obj/machinery/faxmachine/New()
+ ..()
+ allfaxes += src
+
+ if( !("[department]" in alldepartments) )
+ alldepartments += department
+
/obj/machinery/faxmachine/process()
return 0
@@ -26,7 +42,7 @@
/obj/machinery/faxmachine/attack_hand(mob/user as mob)
user.set_machine(src)
- var/dat = "Central Command Fax Machine "
+ var/dat = "Fax Machine "
var/scan_name
if(scan)
@@ -54,14 +70,15 @@
else
dat += "Send "
- dat += "Currently sending: [tofax.name]"
+ dat += "Currently sending: [tofax.name] "
+ dat += "Sending to:[dpt] "
else
if(sendcooldown)
- dat += "Please insert paper to send to Central Command via secure connection.
"
+ dat += "Please insert paper to send via secure connection.
"
dat += "Transmitter arrays realigning. Please stand by. "
else
- dat += "Please insert paper to send to Central Command via secure connection.
"
+ dat += "Please insert paper to send via secure connection.
"
else
dat += "Proper authentication is required to use this device.
"
@@ -76,18 +93,29 @@
/obj/machinery/faxmachine/Topic(href, href_list)
if(href_list["send"])
if(tofax)
- Centcomm_fax(tofax.info, tofax.name, usr)
- usr << "Message transmitted."
- sendcooldown = 1
- spawn(3000) // three minute cooldown. might mess with this number a bit as time goes on
+
+ if(dpt == "Central Command")
+ Centcomm_fax(tofax.info, tofax.name, usr)
+ sendcooldown = 1800
+
+ else
+ SendFax(tofax.info, tofax.name, usr, dpt)
+ sendcooldown = 600
+
+ usr << "Message transmitted successfully."
+
+ spawn(sendcooldown) // cooldown time
sendcooldown = 0
if(href_list["remove"])
if(tofax)
- tofax.loc = usr.loc
- usr.put_in_hands(tofax)
- usr << "You take the paper out of \the [src]."
- tofax = null
+ if(!ishuman(usr))
+ usr << "You can't do it."
+ else
+ tofax.loc = usr.loc
+ usr.put_in_hands(tofax)
+ usr << "You take the paper out of \the [src]."
+ tofax = null
if(href_list["scan"])
if (scan)
@@ -107,6 +135,9 @@
scan = I
authenticated = 0
+ if(href_list["dept"])
+ dpt = input(usr, "Which department?", "Choose a department", "") as null|anything in alldepartments
+
if(href_list["auth"])
if ( (!( authenticated ) && (scan)) )
if (check_access(scan))
@@ -148,3 +179,20 @@
var/msg = "\blue CENTCOMM FAX: [key_name(Sender, 1)] (PP) (VV) (SM) (JMP) (CA) (RPLY): Receiving '[sentname]' via secure connection ... view message"
admins << msg
+
+proc/SendFax(var/sent, var/sentname, var/mob/Sender, var/dpt)
+
+ for(var/obj/machinery/faxmachine/F in allfaxes)
+ if( F.department == dpt )
+ if(! (F.stat & (BROKEN|NOPOWER) ) )
+
+ flick("faxreceive", F)
+
+ // give the sprite some time to flick
+ spawn(20)
+ var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( F.loc )
+ P.name = "[sentname]"
+ P.info = "[sent]"
+ P.update_icon()
+
+ playsound(F.loc, "sound/items/polaroid1.ogg", 50, 1)
diff --git a/code/ZAS/Debug.dm b/code/ZAS/Debug.dm
index 5ac704cf9fa..39f5a7caabd 100644
--- a/code/ZAS/Debug.dm
+++ b/code/ZAS/Debug.dm
@@ -134,6 +134,7 @@ zone/proc/DebugDisplay(client/client)
client/proc/TestZASRebuild()
+ set category = "Debug"
// var/turf/turf = get_turf(mob)
var/zone/current_zone = mob.loc:zone
if(!current_zone)
@@ -155,7 +156,7 @@ client/proc/TestZASRebuild()
for(var/direction in cardinal)
var/turf/simulated/adjacent = get_step(current, direction)
- if(!current.ZAirPass(adjacent))
+ if(!current.ZCanPass(adjacent))
continue
if(turfs.Find(adjacent))
current_adjacents += adjacent
@@ -210,4 +211,9 @@ client/proc/TestZASRebuild()
for(var/turf/current in turfs)
current.overlays -= overlays
- return final_arrangement
\ No newline at end of file
+ return final_arrangement
+
+/client/proc/ZASSettings()
+ set category = "Debug"
+
+ vsc.SetDefault(mob)
\ No newline at end of file
diff --git a/code/ZAS/FEA_gas_mixture.dm b/code/ZAS/FEA_gas_mixture.dm
index 3eccad7e913..9a829633e2b 100644
--- a/code/ZAS/FEA_gas_mixture.dm
+++ b/code/ZAS/FEA_gas_mixture.dm
@@ -14,6 +14,20 @@ What are the archived variables for?
#define QUANTIZE(variable) (round(variable,0.0001))
#define TRANSFER_FRACTION 5 //What fraction (1/#) of the air difference to try and transfer
+/hook/startup/proc/createGasOverlays()
+ plmaster = new /obj/effect/overlay()
+ plmaster.icon = 'icons/effects/tile_effects.dmi'
+ plmaster.icon_state = "plasma"
+ plmaster.layer = FLY_LAYER
+ plmaster.mouse_opacity = 0
+
+ slmaster = new /obj/effect/overlay()
+ slmaster.icon = 'icons/effects/tile_effects.dmi'
+ slmaster.icon_state = "sleeping_agent"
+ slmaster.layer = FLY_LAYER
+ slmaster.mouse_opacity = 0
+ return 1
+
/datum/gas/sleeping_agent/specific_heat = 40 //These are used for the "Trace Gases" stuff, but is buggy.
/datum/gas/oxygen_agent_b/specific_heat = 300
diff --git a/code/ZAS/Fire.dm b/code/ZAS/Fire.dm
index a40746f52f6..ddc06106f38 100644
--- a/code/ZAS/Fire.dm
+++ b/code/ZAS/Fire.dm
@@ -75,12 +75,12 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh)
//since the air is processed in fractions, we need to make sure not to have any minuscle residue or
//the amount of moles might get to low for some functions to catch them and thus result in wonky behaviour
- if(air_contents.oxygen < 0.001)
+ if(air_contents.oxygen < 0.1)
air_contents.oxygen = 0
- if(air_contents.toxins < 0.001)
+ if(air_contents.toxins < 0.1)
air_contents.toxins = 0
if(fuel)
- if(fuel.moles < 0.001)
+ if(fuel.moles < 0.1)
air_contents.trace_gases.Remove(fuel)
//check if there is something to combust
@@ -200,7 +200,7 @@ datum/gas_mixture/proc/zburn(obj/effect/decal/cleanable/liquid_fuel/liquid, forc
if(liquid)
//Liquid Fuel
- if(liquid.amount <= 0)
+ if(liquid.amount <= 0.1)
del liquid
else
total_fuel += liquid.amount
@@ -257,9 +257,9 @@ datum/gas_mixture/proc/check_recombustability(obj/effect/decal/cleanable/liquid_
if(oxygen && (toxins || fuel || liquid))
if(liquid)
return 1
- if (toxins)
+ if(toxins >= 0.1)
return 1
- if(fuel)
+ if(fuel && fuel.moles >= 0.1)
return 1
return 0
@@ -272,9 +272,9 @@ datum/gas_mixture/proc/check_combustability(obj/effect/decal/cleanable/liquid_fu
if(oxygen && (toxins || fuel || liquid))
if(liquid)
return 1
- if (toxins >= 0.7)
+ if (toxins >= 0.1)
return 1
- if(fuel && fuel.moles >= 1.4)
+ if(fuel && fuel.moles >= 0.1)
return 1
return 0
diff --git a/code/ZAS/Plasma.dm b/code/ZAS/Plasma.dm
index 9f0e95f6617..716ea216403 100644
--- a/code/ZAS/Plasma.dm
+++ b/code/ZAS/Plasma.dm
@@ -118,12 +118,12 @@ obj/var/contaminated = 0
/mob/living/carbon/human/proc/burn_eyes()
//The proc that handles eye burning.
if(prob(20)) src << "\red Your eyes burn!"
- eye_stat += 2.5
+ var/datum/organ/internal/eyes/E = internal_organs["eyes"]
+ E.damage += 2.5
eye_blurry = min(eye_blurry+1.5,50)
- if (prob(max(0,eye_stat - 20) + 1) &&!eye_blind)
+ if (prob(max(0,E.damage - 15) + 1) &&!eye_blind)
src << "\red You are blinded!"
eye_blind += 20
- eye_stat = 0
/mob/living/carbon/human/proc/pl_head_protected()
//Checks if the head is adequately sealed.
diff --git a/code/ZAS/Variable Settings.dm b/code/ZAS/Variable Settings.dm
index 5dd951fe52e..92841a02dcd 100644
--- a/code/ZAS/Variable Settings.dm
+++ b/code/ZAS/Variable Settings.dm
@@ -67,7 +67,7 @@ var/global/vs_control/vsc = new
var/connection_insulation = 1
var/connection_insulation_NAME = "Connections - Insulation"
- var/connection_insulation_DESC = "How insulative a connection is, in terms of heat transfer. 1 is perfectly insulative, and 0 is perfectly conductive."
+ var/connection_insulation_DESC = "Boolean, should doors forbid heat transfer?"
var/connection_temperature_delta = 10
var/connection_temperature_delta_NAME = "Connections - Temperature Difference"
@@ -288,6 +288,7 @@ var/global/vs_control/vsc = new
airflow_speed_decay = 1
airflow_delay = 20
airflow_mob_slowdown = 3
+ connection_insulation = 0
world << "\blue [key_name(user)] changed the global plasma/ZAS settings to \"[def]\""
diff --git a/code/ZAS/ZAS_Turfs.dm b/code/ZAS/ZAS_Turfs.dm
index 12ac2df2445..43ea2887627 100644
--- a/code/ZAS/ZAS_Turfs.dm
+++ b/code/ZAS/ZAS_Turfs.dm
@@ -39,8 +39,6 @@
/turf/simulated/var/tmp/datum/gas_mixture/air
-/turf/simulated/var/tmp/processing = 1
-
/turf/simulated/var/tmp/air_check_directions = 0 //Do not modify this, just add turf to air_master.tiles_to_update
/turf/simulated/var/tmp/unsim_check_directions = 0 //See above.
@@ -61,8 +59,6 @@
overlays.Add(slmaster)
/turf/simulated/New()
- ..()
-
if(!blocks_air)
air = new
@@ -84,6 +80,8 @@
if(istype(target))
air_master.tiles_to_update |= target
+ . = ..()
+
/turf/simulated/Del()
if(active_hotspot)
del(active_hotspot)
@@ -168,23 +166,73 @@
if(src in air_master.turfs_with_connections)
air_master.AddConnectionToCheck(air_master.turfs_with_connections[src])
- if(zone && CanPass(null, src, 0, 0))
-
+ if(zone && !air_master.zones_needing_rebuilt.Find(zone))
for(var/direction in cardinal)
var/turf/T = get_step(src,direction)
if(!istype(T))
continue
- //I can connect to air or space in this direction
- if((air_check_directions & direction && !(air_directions_archived & direction)) || \
- (unsim_check_directions & direction && !(unsim_directions_archived & direction)))
- ZConnect(src,T)
- zone.ActivateIfNeeded()
- if(T.zone) T.zone.ActivateIfNeeded()
+ //I can connect to air in this direction
+ if(air_check_directions & direction || unsim_check_directions & direction)
+
+ //If either block air, we must look to see if the adjacent turfs need rebuilt.
+ if(!CanPass(null, T, 0, 0))
+
+ //Target blocks air
+ if(!T.CanPass(null, T, 0, 0))
+ var/turf/NT = get_step(T, direction)
+
+ //If that turf is in my zone still, rebuild.
+ if(istype(NT,/turf/simulated) && NT in zone.contents)
+ air_master.zones_needing_rebuilt.Add(zone)
+
+ //If that is an unsimulated tile in my zone, see if we need to rebuild or just remove.
+ else if(istype(NT) && NT in zone.unsimulated_tiles)
+ var/consider_rebuild = 0
+ for(var/d in cardinal)
+ var/turf/UT = get_step(NT,d)
+ if(istype(UT, /turf/simulated) && UT.zone == zone && UT.CanPass(null, NT, 0, 0)) //If we find a neighboring tile that is in the same zone, check if we need to rebuild
+ consider_rebuild = 1
+ break
+ if(consider_rebuild)
+ air_master.zones_needing_rebuilt.Add(zone) //Gotta check if we need to rebuild, dammit
+ else
+ zone.RemoveTurf(NT) //Not adjacent to anything, and unsimulated. Goodbye~
+
+ //To make a closed connection through closed door.
+ ZConnect(T, src)
+
+ //If I block air.
+ else if(T.zone && !air_master.zones_needing_rebuilt.Find(T.zone))
+ var/turf/NT = get_step(src, reverse_direction(direction))
+
+ //If I am splitting a zone, rebuild.
+ if(istype(NT,/turf/simulated) && (NT in T.zone.contents || (NT.zone && T in NT.zone.contents)))
+ air_master.zones_needing_rebuilt.Add(T.zone)
+
+ //If NT is unsimulated, parse if I should remove it or rebuild.
+ else if(istype(NT) && NT in T.zone.unsimulated_tiles)
+ var/consider_rebuild = 0
+ for(var/d in cardinal)
+ var/turf/UT = get_step(NT,d)
+ if(istype(UT, /turf/simulated) && UT.zone == T.zone && UT.CanPass(null, NT, 0, 0)) //If we find a neighboring tile that is in the same zone, check if we need to rebuild
+ consider_rebuild = 1
+ break
+
+ //Needs rebuilt.
+ if(consider_rebuild)
+ air_master.zones_needing_rebuilt.Add(T.zone)
+
+ //Not adjacent to anything, and unsimulated. Goodbye~
+ else
+ T.zone.RemoveTurf(NT)
+
+ else
+ //Produce connection through open door.
+ ZConnect(src,T)
//Something like a wall was built, changing the geometry.
- else if((!(air_check_directions & direction) && air_directions_archived & direction) || \
- (!(unsim_check_directions & direction) && unsim_directions_archived & direction))
+ else if(air_directions_archived & direction || unsim_directions_archived & direction)
var/turf/NT = get_step(T, direction)
//If the tile is in our own zone, and we cannot connect to it, better rebuild.
@@ -207,16 +255,12 @@
//The unsimulated turf is adjacent to another one of our zone's turfs,
// better rebuild to be sure we didn't get cut in twain
if(consider_rebuild)
- air_master.zones_needing_rebuilt.Add(zone)
+ air_master.zones_needing_rebuilt.Add(NT.zone)
//Not adjacent to anything, and unsimulated. Goodbye~
else
zone.RemoveTurf(NT)
- if(air_check_directions)
- processing = 1
- else
- processing = 0
return 1
/turf/proc/HasDoor(turf/O)
diff --git a/code/ZAS/ZAS_Zones.dm b/code/ZAS/ZAS_Zones.dm
index cd77fbbbf21..c7387254d4d 100644
--- a/code/ZAS/ZAS_Zones.dm
+++ b/code/ZAS/ZAS_Zones.dm
@@ -27,7 +27,6 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs
var/interactions_with_unsim = 0
var/progress = "nothing"
-
//CREATION AND DELETION
/zone/New(turf/start)
. = ..()
@@ -47,14 +46,23 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs
//Generate the gas_mixture for use in txhis zone by using the average of the gases
//defined at startup.
+ //Changed to try and find the source of the error.
air = new
air.group_multiplier = contents.len
for(var/turf/simulated/T in contents)
- air.oxygen += T.oxygen / air.group_multiplier
- air.nitrogen += T.nitrogen / air.group_multiplier
- air.carbon_dioxide += T.carbon_dioxide / air.group_multiplier
- air.toxins += T.toxins / air.group_multiplier
- air.temperature += T.temperature / air.group_multiplier
+ if(!T.air)
+ continue
+ air.oxygen += T.air.oxygen / air.group_multiplier
+ air.nitrogen += T.air.nitrogen / air.group_multiplier
+ air.carbon_dioxide += T.air.carbon_dioxide / air.group_multiplier
+ air.toxins += T.air.toxins / air.group_multiplier
+ air.temperature += T.air.temperature / air.group_multiplier
+ for(var/datum/gas/trace in T.air.trace_gases)
+ var/datum/gas/corresponding_gas = locate(trace.type) in air.trace_gases
+ if(!corresponding_gas)
+ corresponding_gas = new trace.type()
+ air.trace_gases.Add(corresponding_gas)
+ corresponding_gas.moles += trace.moles
air.update_values()
//Add this zone to the global list.
@@ -69,40 +77,57 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs
for(var/turf/simulated/T in contents)
RemoveTurf(T)
air_master.ReconsiderTileZone(T)
- for(var/zone/Z in connected_zones)
- if(src in Z.connected_zones)
- Z.connected_zones.Remove(src)
- air_master.AddConnectionToCheck(connections)
if(air_master)
- air_master.zones.Remove(src)
- air_master.active_zones.Remove(src)
- air_master.zones_needing_rebuilt.Remove(src)
+ air_master.AddConnectionToCheck(connections)
+
air = null
+
. = ..()
//Handles deletion via garbage collection.
/zone/proc/SoftDelete()
+ air = null
+
if(air_master)
air_master.zones.Remove(src)
air_master.active_zones.Remove(src)
air_master.zones_needing_rebuilt.Remove(src)
- air = null
+ air_master.AddConnectionToCheck(connections)
+
+ connections = null
+ for(var/connection/C in direct_connections)
+ if(C.A.zone == src)
+ C.A.zone = null
+ if(C.B.zone == src)
+ C.B.zone = null
+ if(C.zone_A == src)
+ C.zone_A = null
+ if(C.zone_B == src)
+ C.zone_B = null
+ direct_connections = null
//Ensuring the zone list doesn't get clogged with null values.
for(var/turf/simulated/T in contents)
RemoveTurf(T)
air_master.ReconsiderTileZone(T)
+ contents.Cut()
+
//Removing zone connections and scheduling connection cleanup
for(var/zone/Z in connected_zones)
- if(src in Z.connected_zones)
- Z.connected_zones.Remove(src)
- connected_zones = null
+ Z.connected_zones.Remove(src)
+ if(!Z.connected_zones.len)
+ Z.connected_zones = null
- air_master.AddConnectionToCheck(connections)
- connections = null
+ if(Z.closed_connection_zones)
+ Z.closed_connection_zones.Remove(src)
+ if(!Z.closed_connection_zones.len)
+ Z.closed_connection_zones = null
+
+ connected_zones = null
+ closed_connection_zones = null
return 1
@@ -161,6 +186,10 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs
if(!unsim_air_needs_update && air_unsim) //if air_unsim doesn't exist, we need to create it even if we don't need an update.
return
+ //Tempfix.
+ if(!air)
+ return
+
unsim_air_needs_update = 0
if(!air_unsim)
@@ -340,25 +369,26 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs
Z.interactions_with_neighbors++
interactions_with_neighbors++
- for(var/zone/Z in closed_connection_zones)
- //If that zone has already processed, skip it.
- if(Z.last_update > last_update)
- continue
-
- var/handle_temperature = abs(air.temperature - Z.air.temperature) > vsc.connection_temperature_delta
-
- if(Z.status == ZONE_SLEEPING)
- if (handle_temperature)
- Z.SetStatus(ZONE_ACTIVE)
- else
+ if(!vsc.connection_insulation)
+ for(var/zone/Z in closed_connection_zones)
+ //If that zone has already processed, skip it.
+ if(Z.last_update > last_update || !Z.air)
continue
- if(air && Z.air)
- if( handle_temperature )
- ShareHeat(air, Z.air, closed_connection_zones[Z])
+ var/handle_temperature = abs(air.temperature - Z.air.temperature) > vsc.connection_temperature_delta
- Z.interactions_with_neighbors++
- interactions_with_neighbors++
+ if(Z.status == ZONE_SLEEPING)
+ if (handle_temperature)
+ Z.SetStatus(ZONE_ACTIVE)
+ else
+ continue
+
+ if(air && Z.air)
+ if( handle_temperature )
+ ShareHeat(air, Z.air, closed_connection_zones[Z])
+
+ Z.interactions_with_neighbors++
+ interactions_with_neighbors++
if(!interactions_with_neighbors && !interactions_with_unsim)
SetStatus(ZONE_SLEEPING)
@@ -633,6 +663,18 @@ proc/ShareSpace(datum/gas_mixture/A, list/unsimulated_tiles, dbg_output)
proc/ShareHeat(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles)
+ //This implements a simplistic version of the Stefan-Boltzmann law.
+ var/energy_delta = ((A.temperature - B.temperature) ** 4) * 5.6704e-8 * connecting_tiles * 2.5
+ var/maximum_energy_delta = max(0, min(A.temperature * A.heat_capacity() * A.group_multiplier, B.temperature * B.heat_capacity() * B.group_multiplier))
+ if(maximum_energy_delta > abs(energy_delta))
+ if(energy_delta < 0)
+ maximum_energy_delta *= -1
+ energy_delta = maximum_energy_delta
+
+ A.temperature -= energy_delta / (A.heat_capacity() * A.group_multiplier)
+ B.temperature += energy_delta / (B.heat_capacity() * B.group_multiplier)
+
+ /* This was bad an I feel bad.
//Shares a specific ratio of gas between mixtures using simple weighted averages.
var
//WOOT WOOT TOUCH THIS AND YOU ARE A RETARD
@@ -655,7 +697,7 @@ proc/ShareHeat(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles)
A.temperature = max(0, (A.temperature - temp_avg) * (1- (ratio / max(1,A.group_multiplier)) ) + temp_avg )
B.temperature = max(0, (B.temperature - temp_avg) * (1- (ratio / max(1,B.group_multiplier)) ) + temp_avg )
-
+ */
///////////////////
//Zone Rebuilding//
@@ -715,9 +757,9 @@ zone/proc/Rebuild()
current_adjacents = list()
for(var/direction in cardinal)
- if( !(current.air_check_directions & direction))
- continue
var/turf/simulated/adjacent = get_step(current, direction)
+ if(!current.ZCanPass(adjacent))
+ continue
if(adjacent in turfs)
current_adjacents += adjacent
adjacent_id = turfs[adjacent]
@@ -747,6 +789,9 @@ zone/proc/Rebuild()
final_arrangement[current_identifier] = list(current)
else
+ //Sanity check.
+ if(!islist(final_arrangement[current_identifier]))
+ final_arrangement[current_identifier] = list()
final_arrangement[current_identifier] += current
//lazy but fast
diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm
index 0b535a44c39..e2c04299f1c 100644
--- a/code/__HELPERS/game.dm
+++ b/code/__HELPERS/game.dm
@@ -142,7 +142,7 @@
if(ismob(A))
var/mob/M = A
if(client_check && !M.client)
- L = recursive_mob_check(A, L, recursion_limit - 1, client_check, sight_check, include_radio)
+ L |= recursive_mob_check(A, L, recursion_limit - 1, client_check, sight_check, include_radio)
continue
if(sight_check && !isInSight(A, O))
continue
@@ -155,7 +155,7 @@
L |= A
if(isobj(A) || ismob(A))
- L = recursive_mob_check(A, L, recursion_limit - 1, client_check, sight_check, include_radio)
+ L |= recursive_mob_check(A, L, recursion_limit - 1, client_check, sight_check, include_radio)
return L
// The old system would loop through lists for a total of 5000 per function call, in an empty server.
@@ -182,7 +182,7 @@
hear += A
if(isobj(A) || ismob(A))
- hear = recursive_mob_check(A, hear, 3, 1, 0, 1)
+ hear |= recursive_mob_check(A, hear, 3, 1, 0, 1)
return hear
@@ -209,8 +209,9 @@
if(M)
var/turf/ear = get_turf(M)
if(ear)
- if(speaker_coverage[ear])
- . |= M
+ // Ghostship is magic: Ghosts can hear radio chatter from anywhere
+ if(speaker_coverage[ear] || (istype(M, /mob/dead/observer) && (M.client) && (M.client.prefs.toggles & CHAT_GHOSTRADIO)))
+ . |= M // Since we're already looping through mobs, why bother using |= ? This only slows things down.
return .
#define SIGN(X) ((X<0)?-1:1)
@@ -327,3 +328,41 @@ proc/isInSight(var/atom/A, var/atom/B)
spawn(delay)
for(var/client/C in group)
C.screen -= O
+
+datum/projectile_data
+ var/src_x
+ var/src_y
+ var/time
+ var/distance
+ var/power_x
+ var/power_y
+ var/dest_x
+ var/dest_y
+
+/datum/projectile_data/New(var/src_x, var/src_y, var/time, var/distance, \
+ var/power_x, var/power_y, var/dest_x, var/dest_y)
+ src.src_x = src_x
+ src.src_y = src_y
+ src.time = time
+ src.distance = distance
+ src.power_x = power_x
+ src.power_y = power_y
+ src.dest_x = dest_x
+ src.dest_y = dest_y
+
+/proc/projectile_trajectory(var/src_x, var/src_y, var/rotation, var/angle, var/power)
+
+ // returns the destination (Vx,y) that a projectile shot at [src_x], [src_y], with an angle of [angle],
+ // rotated at [rotation] and with the power of [power]
+ // Thanks to VistaPOWA for this function
+
+ var/power_x = power * cos(angle)
+ var/power_y = power * sin(angle)
+ var/time = 2* power_y / 10 //10 = g
+
+ var/distance = time * power_x
+
+ var/dest_x = src_x + distance*sin(rotation);
+ var/dest_y = src_y + distance*cos(rotation);
+
+ return new /datum/projectile_data(src_x, src_y, time, distance, power_x, power_y, dest_x, dest_y)
diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm
index ce8d788f25f..ff853eca2f2 100644
--- a/code/__HELPERS/global_lists.dm
+++ b/code/__HELPERS/global_lists.dm
@@ -42,7 +42,7 @@ var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel", "Satchel Al
/////Initial Building/////
//////////////////////////
-/proc/make_datum_references_lists()
+/hook/startup/proc/makeDatumRefLists()
var/list/paths
//Hair - Initialise all /datum/sprite_accessory/hair into an list indexed by hair-style name
@@ -94,9 +94,11 @@ var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel", "Satchel Al
var/datum/species/S = new T
all_species[S.name] = S
- if(S.flags & WHITELISTED)
+ if(S.flags & IS_WHITELISTED)
whitelisted_species += S.name
+ return 1
+
/* // Uncomment to debug chemical reaction list.
/client/verb/debug_chemical_list()
diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm
index cfca598adbc..0ca515486b4 100644
--- a/code/__HELPERS/icons.dm
+++ b/code/__HELPERS/icons.dm
@@ -773,4 +773,14 @@ proc
for(var/O in A.overlays)
var/image/I = O
composite.Blend(icon(I.icon, I.icon_state, I.dir, 1), ICON_OVERLAY)
- return composite
\ No newline at end of file
+ return composite
+
+proc/adjust_brightness(var/color, var/value)
+ if (!color) return "#FFFFFF"
+ if (!value) return color
+
+ var/list/RGB = ReadRGB(color)
+ RGB[1] = Clamp(RGB[1]+value,0,255)
+ RGB[2] = Clamp(RGB[2]+value,0,255)
+ RGB[3] = Clamp(RGB[3]+value,0,255)
+ return rgb(RGB[1],RGB[2],RGB[3])
\ No newline at end of file
diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm
index a493aa9d080..af77addeab0 100644
--- a/code/__HELPERS/text.dm
+++ b/code/__HELPERS/text.dm
@@ -195,32 +195,10 @@ proc/checkhtml(var/t)
* Text modification
*/
/proc/replacetext(text, find, replacement)
- var/find_len = length(find)
- if(find_len < 1) return text
- . = ""
- var/last_found = 1
- while(1)
- var/found = findtext(text, find, last_found, 0)
- . += copytext(text, last_found, found)
- if(found)
- . += replacement
- last_found = found + find_len
- continue
- return .
+ return list2text(text2list(text, find), replacement)
/proc/replacetextEx(text, find, replacement)
- var/find_len = length(find)
- if(find_len < 1) return text
- . = ""
- var/last_found = 1
- while(1)
- var/found = findtextEx(text, find, last_found, 0)
- . += copytext(text, last_found, found)
- if(found)
- . += replacement
- last_found = found + find_len
- continue
- return .
+ return list2text(text2listEx(text, find), replacement)
//Adds 'u' number of zeros ahead of the text 't'
/proc/add_zero(t, u)
@@ -287,27 +265,6 @@ proc/checkhtml(var/t)
return message
return copytext(message, 1, length + 1)
-/*
- * Misc
- */
-
-/proc/stringsplit(txt, character)
- var/cur_text = txt
- var/last_found = 1
- var/found_char = findtext(cur_text,character)
- var/list/list = list()
- if(found_char)
- var/fs = copytext(cur_text,last_found,found_char)
- list += fs
- last_found = found_char+length(character)
- found_char = findtext(cur_text,character,last_found)
- while(found_char)
- var/found_string = copytext(cur_text,last_found,found_char)
- last_found = found_char+length(character)
- list += found_string
- found_char = findtext(cur_text,character,last_found)
- list += copytext(cur_text,last_found,length(cur_text)+1)
- return list
/proc/stringmerge(var/text,var/compare,replace = "*")
//This proc fills in all spaces with the "replace" var (* by default) with whatever
@@ -346,4 +303,4 @@ proc/checkhtml(var/t)
var/new_text = ""
for(var/i = length(text); i > 0; i--)
new_text += copytext(text, i, i+1)
- return new_text
\ No newline at end of file
+ return new_text
diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm
index e180f2092d6..4e6287a5d25 100644
--- a/code/__HELPERS/type2type.dm
+++ b/code/__HELPERS/type2type.dm
@@ -83,22 +83,94 @@
return hex
-//Attaches each element of a list to a single string seperated by 'seperator'.
-/proc/dd_list2text(var/list/the_list, separator)
- var/total = the_list.len
- if(!total)
- return
- var/count = 2
- var/newText = "[the_list[1]]"
- while(count <= total)
- if(separator)
- newText += separator
- newText += "[the_list[count]]"
- count++
- return newText
+// Concatenates a list of strings into a single string. A seperator may optionally be provided.
+/proc/list2text(list/ls, sep)
+ if(ls.len <= 1) // Early-out code for empty or singleton lists.
+ return ls.len ? ls[1] : ""
+
+ var/l = ls.len // Made local for sanic speed.
+ var/i = 0 // Incremented every time a list index is accessed.
+
+ if(sep <> null)
+ // Macros expand to long argument lists like so: sep, ls[++i], sep, ls[++i], sep, ls[++i], etc...
+ #define S1 sep, ls[++i]
+ #define S4 S1, S1, S1, S1
+ #define S16 S4, S4, S4, S4
+ #define S64 S16, S16, S16, S16
+
+ . = "[ls[++i]]" // Make sure the initial element is converted to text.
+
+ // Having the small concatenations come before the large ones boosted speed by an average of at least 5%.
+ if(l-1 & 0x01) // 'i' will always be 1 here.
+ . = text("[][][]", ., S1) // Append 1 element if the remaining elements are not a multiple of 2.
+ if(l-i & 0x02)
+ . = text("[][][][][]", ., S1, S1) // Append 2 elements if the remaining elements are not a multiple of 4.
+ if(l-i & 0x04)
+ . = text("[][][][][][][][][]", ., S4) // And so on....
+ if(l-i & 0x08)
+ . = text("[][][][][][][][][][][][][][][][][]", ., S4, S4)
+ if(l-i & 0x10)
+ . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16)
+ if(l-i & 0x20)
+ . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
+ [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16, S16)
+ if(l-i & 0x40)
+ . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
+ [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
+ [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
+ [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64)
+ while(l > i) // Chomp through the rest of the list, 128 elements at a time.
+ . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
+ [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
+ [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
+ [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
+ [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
+ [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
+ [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
+ [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64, S64)
+
+ #undef S64
+ #undef S16
+ #undef S4
+ #undef S1
+
+ else
+ // Macros expand to long argument lists like so: ls[++i], ls[++i], ls[++i], etc...
+ #define S1 ls[++i]
+ #define S4 S1, S1, S1, S1
+ #define S16 S4, S4, S4, S4
+ #define S64 S16, S16, S16, S16
+
+ . = "[ls[++i]]" // Make sure the initial element is converted to text.
+
+ if(l-1 & 0x01) // 'i' will always be 1 here.
+ . += S1 // Append 1 element if the remaining elements are not a multiple of 2.
+ if(l-i & 0x02)
+ . = text("[][][]", ., S1, S1) // Append 2 elements if the remaining elements are not a multiple of 4.
+ if(l-i & 0x04)
+ . = text("[][][][][]", ., S4) // And so on...
+ if(l-i & 0x08)
+ . = text("[][][][][][][][][]", ., S4, S4)
+ if(l-i & 0x10)
+ . = text("[][][][][][][][][][][][][][][][][]", ., S16)
+ if(l-i & 0x20)
+ . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S16, S16)
+ if(l-i & 0x40)
+ . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
+ [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64)
+ while(l > i) // Chomp through the rest of the list, 128 elements at a time.
+ . = text("[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
+ [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
+ [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]\
+ [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]", ., S64, S64)
+
+ #undef S64
+ #undef S16
+ #undef S4
+ #undef S1
-//slower then dd_list2text, but correctly processes associative lists.
+//slower then list2text, but correctly processes associative lists.
proc/tg_list2text(list/list, glue=",")
if(!istype(list) || !list.len)
return
@@ -108,62 +180,50 @@ proc/tg_list2text(list/list, glue=",")
return output
-//Converts a text string into a list by splitting the string at each seperator found in text (discarding the seperator)
-//Returns an empty list if the text cannot be split, or the split text in a list.
-//Not giving a "" seperator will cause the text to be broken into a list of single letters.
-/proc/text2list(text, seperator="\n")
+//Converts a string into a list by splitting the string at each delimiter found. (discarding the seperator)
+/proc/text2list(text, delimiter="\n")
+ var/delim_len = length(delimiter)
+ if(delim_len < 1) return list(text)
. = list()
+ var/last_found = 1
+ var/found
+ do
+ found = findtext(text, delimiter, last_found, 0)
+ . += copytext(text, last_found, found)
+ last_found = found + delim_len
+ while(found)
- var/text_len = length(text) //length of the input text
- var/seperator_len = length(seperator) //length of the seperator text
-
- if(text_len >= seperator_len)
- var/i
- var/last_i = 1
-
- for(i=1,i<=(text_len+1-seperator_len),i++)
- if( cmptext(copytext(text,i,i+seperator_len), seperator) )
- if(i != last_i)
- . += copytext(text,last_i,i)
- last_i = i + seperator_len
-
- if(last_i <= text_len)
- . += copytext(text, last_i, 0)
- else
- . += text
- return .
-
-//Converts a text string into a list by splitting the string at each seperator found in text (discarding the seperator)
-//Returns an empty list if the text cannot be split, or the split text in a list.
-//Not giving a "" seperator will cause the text to be broken into a list of single letters.
//Case Sensitive!
-/proc/text2listEx(text, seperator="\n")
+/proc/text2listEx(text, delimiter="\n")
+ var/delim_len = length(delimiter)
+ if(delim_len < 1) return list(text)
. = list()
-
- var/text_len = length(text) //length of the input text
- var/seperator_len = length(seperator) //length of the seperator text
-
- if(text_len >= seperator_len)
- var/i
- var/last_i = 1
-
- for(i=1,i<=(text_len+1-seperator_len),i++)
- if( cmptextEx(copytext(text,i,i+seperator_len), seperator) )
- if(i != last_i)
- . += copytext(text,last_i,i)
- last_i = i + seperator_len
-
- if(last_i <= text_len)
- . += copytext(text, last_i, 0)
- else
- . += text
- return .
+ var/last_found = 1
+ var/found
+ do
+ found = findtextEx(text, delimiter, last_found, 0)
+ . += copytext(text, last_found, found)
+ last_found = found + delim_len
+ while(found)
//Splits the text of a file at seperator and returns them in a list.
/proc/file2list(filename, seperator="\n")
return text2list(return_file_text(filename),seperator)
+//Turns a direction into text
+
+/proc/num2dir(direction)
+ switch(direction)
+ if(1.0) return NORTH
+ if(2.0) return SOUTH
+ if(4.0) return EAST
+ if(8.0) return WEST
+ else
+ world.log << "UNKNOWN DIRECTION: [direction]"
+
+
+
//Turns a direction into text
/proc/dir2text(direction)
switch(direction)
@@ -261,4 +321,5 @@ proc/tg_list2text(list/list, glue=",")
switch(ui_style)
if("old") return 'icons/mob/screen1_old.dmi'
if("Orange") return 'icons/mob/screen1_Orange.dmi'
- else return 'icons/mob/screen1_Midnight.dmi'
+ if("Midnight") return 'icons/mob/screen1_Midnight.dmi'
+ else return 'icons/mob/screen1_White.dmi'
diff --git a/code/_onclick/adjacent.dm b/code/_onclick/adjacent.dm
index c02737400ba..b39df751896 100644
--- a/code/_onclick/adjacent.dm
+++ b/code/_onclick/adjacent.dm
@@ -46,7 +46,7 @@
continue // could not leave T0 in that direction
var/turf/T1 = get_step(T0,d)
- if(!T1 || T1.density || !T1.ClickCross(get_dir(T1,T0) & get_dir(T1,src), border_only = 0))
+ if(!T1 || T1.density || !T1.ClickCross(get_dir(T1,T0) | get_dir(T1,src), border_only = 0))
continue // couldn't enter or couldn't leave T1
if(!src.ClickCross(get_dir(src,T1), border_only = 1, target_atom = target))
diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm
index cb840a1d90e..112c3431e52 100644
--- a/code/_onclick/ai.dm
+++ b/code/_onclick/ai.dm
@@ -55,6 +55,7 @@
RestrainedClickOn(A)
else
*/
+ A.add_hiddenprint(src)
A.attack_ai(src)
/*
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index 5ce15be96e7..fd0b658aa0b 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -291,7 +291,7 @@
// Simple helper to face what you clicked on, in case it should be needed in more than one place
/mob/proc/face_atom(var/atom/A)
- if( buckled || !A || !x || !y || !A.x || !A.y ) return
+ if( stat || buckled || !A || !x || !y || !A.x || !A.y ) return
var/dx = A.x - x
var/dy = A.y - y
if(!dx && !dy) return
diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm
index 640a09d045f..d86faacbd1f 100644
--- a/code/_onclick/cyborg.dm
+++ b/code/_onclick/cyborg.dm
@@ -48,6 +48,7 @@
// Cyborgs have no range-checking unless there is item use
if(!W)
+ A.add_hiddenprint(src)
A.attack_robot(src)
return
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
index 618858d5438..98e2fda1862 100644
--- a/code/_onclick/hud/hud.dm
+++ b/code/_onclick/hud/hud.dm
@@ -166,9 +166,11 @@ datum/hud/New(mob/owner)
if(!ismob(mymob)) return 0
if(!mymob.client) return 0
var/ui_style = ui_style2icon(mymob.client.prefs.UI_style)
+ var/ui_color = mymob.client.prefs.UI_style_color
+ var/ui_alpha = mymob.client.prefs.UI_style_alpha
if(ishuman(mymob))
- human_hud(ui_style) // Pass the player the UI style chosen in preferences
+ human_hud(ui_style, ui_color, ui_alpha) // Pass the player the UI style chosen in preferences
else if(ismonkey(mymob))
monkey_hud(ui_style)
else if(isbrain(mymob))
@@ -186,14 +188,15 @@ datum/hud/New(mob/owner)
//Triggered when F12 is pressed (Unless someone changed something in the DMF)
-/mob/verb/button_pressed_F12()
+/mob/verb/button_pressed_F12(var/full = 0 as null)
set name = "F12"
set hidden = 1
if(hud_used)
if(ishuman(src))
- if(!src.client) return
-
+ if(!client) return
+ if(client.view != world.view)
+ return
if(hud_used.hud_shown)
hud_used.hud_shown = 0
if(src.hud_used.adding)
@@ -207,10 +210,15 @@ datum/hud/New(mob/owner)
//Due to some poor coding some things need special treatment:
//These ones are a part of 'adding', 'other' or 'hotkeybuttons' but we want them to stay
- src.client.screen += src.hud_used.l_hand_hud_object //we want the hands to be visible
- src.client.screen += src.hud_used.r_hand_hud_object //we want the hands to be visible
- src.client.screen += src.hud_used.action_intent //we want the intent swticher visible
- src.hud_used.action_intent.screen_loc = ui_acti_alt //move this to the alternative position, where zone_select usually is.
+ if(!full)
+ src.client.screen += src.hud_used.l_hand_hud_object //we want the hands to be visible
+ src.client.screen += src.hud_used.r_hand_hud_object //we want the hands to be visible
+ src.client.screen += src.hud_used.action_intent //we want the intent swticher visible
+ src.hud_used.action_intent.screen_loc = ui_acti_alt //move this to the alternative position, where zone_select usually is.
+ else
+ src.client.screen -= src.healths
+ src.client.screen -= src.internals
+ src.client.screen -= src.gun_setting_icon
//These ones are not a part of 'adding', 'other' or 'hotkeybuttons' but we want them gone.
src.client.screen -= src.zone_sel //zone_sel is a mob variable for some reason.
@@ -223,7 +231,12 @@ datum/hud/New(mob/owner)
src.client.screen += src.hud_used.other
if(src.hud_used.hotkeybuttons && !src.hud_used.hotkey_ui_hidden)
src.client.screen += src.hud_used.hotkeybuttons
-
+ if(src.healths)
+ src.client.screen |= src.healths
+ if(src.internals)
+ src.client.screen |= src.internals
+ if(src.gun_setting_icon)
+ src.client.screen |= src.gun_setting_icon
src.hud_used.action_intent.screen_loc = ui_acti //Restore intent selection to the original position
src.client.screen += src.zone_sel //This one is a special snowflake
diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm
index 32e9e1046ec..ca053f86e6b 100644
--- a/code/_onclick/hud/human.dm
+++ b/code/_onclick/hud/human.dm
@@ -1,4 +1,4 @@
-/datum/hud/proc/human_hud(var/ui_style='icons/mob/screen1_old.dmi')
+/datum/hud/proc/human_hud(var/ui_style='icons/mob/screen1_White.dmi', var/ui_color = "#ffffff", var/ui_alpha = 255)
src.adding = list()
src.other = list()
@@ -73,6 +73,8 @@
using.icon_state = (mymob.m_intent == "run" ? "running" : "walking")
using.screen_loc = ui_movi
using.layer = 20
+ using.color = ui_color
+ using.alpha = ui_alpha
src.adding += using
move_intent = using
@@ -82,6 +84,8 @@
using.icon_state = "act_drop"
using.screen_loc = ui_drop_throw
using.layer = 19
+ using.color = ui_color
+ using.alpha = ui_alpha
src.hotkeybuttons += using
inv_box = new /obj/screen/inventory()
@@ -92,6 +96,8 @@
inv_box.icon_state = "center"
inv_box.screen_loc = ui_iclothing
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.other += inv_box
inv_box = new /obj/screen/inventory()
@@ -102,6 +108,8 @@
inv_box.icon_state = "equip"
inv_box.screen_loc = ui_oclothing
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.other += inv_box
inv_box = new /obj/screen/inventory()
@@ -114,6 +122,9 @@
inv_box.screen_loc = ui_rhand
inv_box.slot_id = slot_r_hand
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
+
src.r_hand_hud_object = inv_box
src.adding += inv_box
@@ -127,6 +138,8 @@
inv_box.screen_loc = ui_lhand
inv_box.slot_id = slot_l_hand
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.l_hand_hud_object = inv_box
src.adding += inv_box
@@ -137,6 +150,8 @@
using.icon_state = "hand1"
using.screen_loc = ui_swaphand1
using.layer = 19
+ using.color = ui_color
+ using.alpha = ui_alpha
src.adding += using
using = new /obj/screen/inventory()
@@ -146,6 +161,8 @@
using.icon_state = "hand2"
using.screen_loc = ui_swaphand2
using.layer = 19
+ using.color = ui_color
+ using.alpha = ui_alpha
src.adding += using
inv_box = new /obj/screen/inventory()
@@ -156,6 +173,8 @@
inv_box.screen_loc = ui_id
inv_box.slot_id = slot_wear_id
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.adding += inv_box
inv_box = new /obj/screen/inventory()
@@ -166,6 +185,8 @@
inv_box.screen_loc = ui_mask
inv_box.slot_id = slot_wear_mask
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.other += inv_box
inv_box = new /obj/screen/inventory()
@@ -176,6 +197,8 @@
inv_box.screen_loc = ui_back
inv_box.slot_id = slot_back
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.adding += inv_box
inv_box = new /obj/screen/inventory()
@@ -185,6 +208,8 @@
inv_box.screen_loc = ui_storage1
inv_box.slot_id = slot_l_store
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.adding += inv_box
inv_box = new /obj/screen/inventory()
@@ -194,6 +219,8 @@
inv_box.screen_loc = ui_storage2
inv_box.slot_id = slot_r_store
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.adding += inv_box
inv_box = new /obj/screen/inventory()
@@ -204,6 +231,8 @@
inv_box.screen_loc = ui_sstore1
inv_box.slot_id = slot_s_store
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.adding += inv_box
using = new /obj/screen()
@@ -212,6 +241,8 @@
using.icon_state = "act_resist"
using.screen_loc = ui_pull_resist
using.layer = 19
+ using.color = ui_color
+ using.alpha = ui_alpha
src.hotkeybuttons += using
using = new /obj/screen()
@@ -220,6 +251,8 @@
using.icon_state = "other"
using.screen_loc = ui_inventory
using.layer = 20
+ using.color = ui_color
+ using.alpha = ui_alpha
src.adding += using
using = new /obj/screen()
@@ -228,6 +261,8 @@
using.icon_state = "act_equip"
using.screen_loc = ui_equip
using.layer = 20
+ using.color = ui_color
+ using.alpha = ui_alpha
src.adding += using
inv_box = new /obj/screen/inventory()
@@ -237,6 +272,8 @@
inv_box.screen_loc = ui_gloves
inv_box.slot_id = slot_gloves
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.other += inv_box
inv_box = new /obj/screen/inventory()
@@ -246,6 +283,8 @@
inv_box.screen_loc = ui_glasses
inv_box.slot_id = slot_glasses
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.other += inv_box
inv_box = new /obj/screen/inventory()
@@ -255,6 +294,8 @@
inv_box.screen_loc = ui_l_ear
inv_box.slot_id = slot_l_ear
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.other += inv_box
inv_box = new /obj/screen/inventory()
@@ -264,6 +305,8 @@
inv_box.screen_loc = ui_r_ear
inv_box.slot_id = slot_r_ear
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.other += inv_box
inv_box = new /obj/screen/inventory()
@@ -273,6 +316,8 @@
inv_box.screen_loc = ui_head
inv_box.slot_id = slot_head
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.other += inv_box
inv_box = new /obj/screen/inventory()
@@ -282,6 +327,8 @@
inv_box.screen_loc = ui_shoes
inv_box.slot_id = slot_shoes
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.other += inv_box
inv_box = new /obj/screen/inventory()
@@ -291,6 +338,8 @@
inv_box.screen_loc = ui_belt
inv_box.slot_id = slot_belt
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.adding += inv_box
mymob.throw_icon = new /obj/screen()
@@ -298,6 +347,8 @@
mymob.throw_icon.icon_state = "act_throw_off"
mymob.throw_icon.name = "throw"
mymob.throw_icon.screen_loc = ui_drop_throw
+ mymob.throw_icon.color = ui_color
+ mymob.throw_icon.alpha = ui_alpha
src.hotkeybuttons += mymob.throw_icon
mymob.oxygen = new /obj/screen()
@@ -382,6 +433,8 @@
mymob.zone_sel = new /obj/screen/zone_sel( null )
mymob.zone_sel.icon = ui_style
+ mymob.zone_sel.color = ui_color
+ mymob.zone_sel.alpha = ui_alpha
mymob.zone_sel.overlays.Cut()
mymob.zone_sel.overlays += image('icons/mob/zone_sel.dmi', "[mymob.zone_sel.selecting]")
@@ -438,28 +491,26 @@
client.screen -= hud_used.item_action_list
+ hud_used.item_action_list = list()
for(var/obj/item/I in src)
- if(I.action_button_name)
- if(hud_used.item_action_list.len < num)
- var/obj/screen/item_action/N = new(hud_used)
- hud_used.item_action_list += N
-
- var/obj/screen/item_action/A = hud_used.item_action_list[num]
-
+ if(I.icon_action_button)
+ var/obj/screen/item_action/A = new(hud_used)
+
+ //A.icon = 'icons/mob/screen1_action.dmi'
+ //A.icon_state = I.icon_action_button
A.icon = ui_style2icon(client.prefs.UI_style)
A.icon_state = "template"
-
- A.overlays = list()
var/image/img = image(I.icon, A, I.icon_state)
img.pixel_x = 0
img.pixel_y = 0
A.overlays += img
- A.name = I.action_button_name
+ if(I.action_button_name)
+ A.name = I.action_button_name
+ else
+ A.name = "Use [I.name]"
A.owner = I
-
- client.screen += hud_used.item_action_list[num]
-
+ hud_used.item_action_list += A
switch(num)
if(1)
A.screen_loc = ui_action_slot1
@@ -473,3 +524,4 @@
A.screen_loc = ui_action_slot5
break //5 slots available, so no more can be added.
num++
+ src.client.screen += src.hud_used.item_action_list
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index a0dcfb9ae9c..ed054ae6c8a 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -36,6 +36,9 @@
if(istype(master, /obj/item/weapon/storage))
var/obj/item/weapon/storage/S = master
S.close(usr)
+ else if(istype(master,/obj/item/clothing/suit/storage))
+ var/obj/item/clothing/suit/storage/S = master
+ S.close(usr)
return 1
@@ -273,37 +276,79 @@
C << "You are not wearing a mask."
return 1
else
- if(istype(C.l_hand, /obj/item/weapon/tank))
- C << "You are now running on internals from the [C.l_hand] on your left hand."
- C.internal = C.l_hand
- else if(istype(C.r_hand, /obj/item/weapon/tank))
- C << "You are now running on internals from the [C.r_hand] on your right hand."
- C.internal = C.r_hand
- else if(ishuman(C))
+ var/list/nicename = null
+ var/list/tankcheck = null
+ var/breathes = "oxygen" //default, we'll check later
+ var/list/contents = list()
+
+ if(ishuman(C))
var/mob/living/carbon/human/H = C
- if(istype(H.s_store, /obj/item/weapon/tank))
- H << "You are now running on internals from the [H.s_store] on your [H.wear_suit]."
- H.internal = H.s_store
- else if(istype(H.belt, /obj/item/weapon/tank))
- H << "You are now running on internals from the [H.belt] on your belt."
- H.internal = H.belt
- else if(istype(H.l_store, /obj/item/weapon/tank))
- H << "You are now running on internals from the [H.l_store] in your left pocket."
- H.internal = H.l_store
- else if(istype(H.r_store, /obj/item/weapon/tank))
- H << "You are now running on internals from the [H.r_store] in your right pocket."
- H.internal = H.r_store
+ breathes = H.species.breath_type
+ nicename = list ("suit", "back", "belt", "right hand", "left hand", "left pocket", "right pocket")
+ tankcheck = list (H.s_store, C.back, H.belt, C.r_hand, C.l_hand, H.l_store, H.r_store)
- //Seperate so CO2 jetpacks are a little less cumbersome.
- if(!C.internal && istype(C.back, /obj/item/weapon/tank))
- C << "You are now running on internals from the [C.back] on your back."
- C.internal = C.back
+ else
+ nicename = list("Right Hand", "Left Hand", "Back")
+ tankcheck = list(C.r_hand, C.l_hand, C.back)
+
+ for(var/i=1, i bestcontents)
+ best = i
+ bestcontents = contents[i]
+
+
+ //We've determined the best container now we set it as our internals
+
+ if(best)
+ C << "You are now running on internals from [tankcheck[best]] on your [nicename[best]]."
+ C.internal = tankcheck[best]
+
+
if(C.internal)
if(C.internals)
C.internals.icon_state = "internal1"
else
- C << "You don't have an oxygen tank."
+ C << "You don't have a[breathes=="oxygen" ? "n oxygen" : addtext(" ",breathes)] tank."
if("act_intent")
usr.a_intent_change("right")
if("help")
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index 821f42ee1b1..1dbaeb1a3f6 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -140,7 +140,7 @@
if(istype(M, /mob/living/carbon/human))
- M:attacked_by(src, user, def_zone)
+ return M:attacked_by(src, user, def_zone)
else
switch(damtype)
if("brute")
diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm
index c326d83df41..869b10c3a1a 100644
--- a/code/_onclick/observer.dm
+++ b/code/_onclick/observer.dm
@@ -37,27 +37,6 @@
// Not all of them require checking, see below
A.attack_ghost(src)
-// This is the ghost's follow verb with an argument
-/mob/dead/observer/proc/ManualFollow(var/atom/target)
- following = target
- if(target)
- src << "\blue Now following [target]"
- spawn(0)
- var/turf/pos = get_turf(src)
- while(loc == pos && target && following == target)
-
- var/turf/T = get_turf(target)
- if(!T)
- break
- if(following != target)
- break
- if(!client)
- break
- loc = T
- pos = loc
- sleep(15)
- following = null
-
// Oh by the way this didn't work with old click code which is why clicking shit didn't spam you
/atom/proc/attack_ghost(mob/dead/observer/user as mob)
if(user.client && user.client.inquisitive_ghost)
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index c7baaddcf98..f58c8e4b4f6 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -18,6 +18,7 @@
var/log_adminwarn = 0 // log warnings admins get about bomb construction and such
var/log_pda = 0 // log pda messages
var/log_hrefs = 0 // logs all links clicked in-game. Could be used for debugging and tracking down exploits
+ var/log_runtime = 0 // logs world.log to a file
var/sql_enabled = 1 // for sql switching
var/allow_admin_ooccolor = 0 // Allows admins with relevant permissions to have their own ooc colour
var/allow_vote_restart = 0 // allow votes to restart
@@ -44,7 +45,8 @@
var/Tickcomp = 0
var/socket_talk = 0 // use socket_talk to communicate with other processes
var/list/resource_urls = null
-
+ var/antag_hud_allowed = 0 // Ghosts can turn on Antagovision to see a HUD of who is the bad guys this round.
+ var/antag_hud_restricted = 0 // Ghosts that turn on Antagovision cannot rejoin the round.
var/list/mode_names = list()
var/list/modes = list() // allowed modes
var/list/votable_modes = list() // votable modes
@@ -62,6 +64,12 @@
var/automute_on = 0 //enables automuting/spam prevention
var/jobs_have_minimal_access = 0 //determines whether jobs use minimal access or expanded access.
+ var/cult_ghostwriter = 1 //Allows ghosts to write in blood in cult rounds...
+ var/cult_ghostwriter_req_cultists = 10 //...so long as this many cultists are active.
+
+ var/disable_player_mice = 0
+ var/uneducated_mice = 0 //Set to 1 to prevent newly-spawned mice from understanding human speech
+
var/usealienwhitelist = 0
var/limitalienplayers = 0
var/alien_to_human_ratio = 0.5
@@ -177,7 +185,7 @@
if(type == "config")
switch (name)
if ("resource_urls")
- config.resource_urls = stringsplit(value, " ")
+ config.resource_urls = text2list(value, " ")
if ("admin_legacy_system")
config.admin_legacy_system = 1
@@ -239,6 +247,9 @@
if ("log_hrefs")
config.log_hrefs = 1
+ if ("log_runtime")
+ config.log_runtime = 1
+
if("allow_admin_ooccolor")
config.allow_admin_ooccolor = 1
@@ -389,6 +400,11 @@
if("ticklag")
Ticklag = text2num(value)
+ if("allow_antag_hud")
+ config.antag_hud_allowed = 1
+ if("antag_hud_restricted")
+ config.antag_hud_restricted = 1
+
if("socket_talk")
socket_talk = text2num(value)
@@ -423,6 +439,12 @@
if("ghost_interaction")
config.ghost_interaction = 1
+ if("disable_player_mice")
+ config.disable_player_mice = 1
+
+ if("uneducated_mice")
+ config.uneducated_mice = 1
+
if("comms_password")
config.comms_password = value
@@ -444,10 +466,15 @@
else //probably windows, if not this should work anyway
config.python_path = "python"
+ if("allow_cult_ghostwriter")
+ config.cult_ghostwriter = 1
+
+ if("req_cult_ghostwriter")
+ config.cult_ghostwriter_req_cultists = value
+
else
diary << "Unknown setting in configuration: '[name]'"
-
else if(type == "game_options")
if(!value)
diary << "Unknown value for setting [name] in [filename]."
diff --git a/code/controllers/hooks-defs.dm b/code/controllers/hooks-defs.dm
new file mode 100644
index 00000000000..cb51229c9fb
--- /dev/null
+++ b/code/controllers/hooks-defs.dm
@@ -0,0 +1,17 @@
+/**
+ * Startup hook.
+ * Called in world.dm when the server starts.
+ */
+/hook/startup
+
+/**
+ * Roundstart hook.
+ * Called in gameticker.dm when a round starts.
+ */
+/hook/roundstart
+
+/**
+ * Roundend hook.
+ * Called in gameticker.dm when a round ends.
+ */
+/hook/roundend
diff --git a/code/controllers/hooks.dm b/code/controllers/hooks.dm
new file mode 100644
index 00000000000..5045da75925
--- /dev/null
+++ b/code/controllers/hooks.dm
@@ -0,0 +1,39 @@
+/**
+ * @file hooks.dm
+ * Implements hooks, a simple way to run code on pre-defined events.
+ */
+
+/** @page hooks Code hooks
+ * @section hooks Hooks
+ * A hook is defined under /hook in the type tree.
+ *
+ * To add some code to be called by the hook, define a proc under the type, as so:
+ * @code
+ /hook/foo/proc/bar()
+ if(1)
+ return 1 //Sucessful
+ else
+ return 0 //Error, or runtime.
+ * @endcode
+ * All hooks must return nonzero on success, as runtimes will force return null.
+ */
+
+/**
+ * Calls a hook, executing every piece of code that's attached to it.
+ * @param hook Identifier of the hook to call.
+ * @returns 1 if all hooked code runs successfully, 0 otherwise.
+ */
+/proc/callHook(hook)
+ var/hook_path = text2path("/hook/[hook]")
+ if(!hook_path)
+ error("Invalid hook '/hook/[hook]' called.")
+ return 0
+
+ var/caller = new hook_path
+ var/status = 1
+ for(var/P in typesof("[hook_path]/proc"))
+ if(!call(caller, P)())
+ error("Hook '[P]' failed or runtimed.")
+ status = 0
+
+ return status
diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm
index 5e7d308a9eb..e0bd38086aa 100644
--- a/code/controllers/master_controller.dm
+++ b/code/controllers/master_controller.dm
@@ -66,6 +66,7 @@ datum/controller/game_controller/proc/setup()
setupgenetics()
setupfactions()
setup_economy()
+ SetupXenoarch()
transfer_controller = new
@@ -296,7 +297,7 @@ datum/controller/game_controller/proc/process_nano()
var/i = 1
while(i<=nanomanager.processing_uis.len)
var/datum/nanoui/ui = nanomanager.processing_uis[i]
- if(ui && ui.src_object && ui.user)
+ if(ui)
ui.process()
i++
continue
diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm
index 1a7d97e99cf..d4e92584229 100644
--- a/code/datums/datacore.dm
+++ b/code/datums/datacore.dm
@@ -1,3 +1,6 @@
+/hook/startup/proc/createDatacore()
+ data_core = new /obj/effect/datacore()
+ return 1
/obj/effect/datacore/proc/manifest(var/nosleep = 0)
spawn()
@@ -104,13 +107,13 @@
var/datum/data/record/L = new()
L.fields["id"] = md5("[H.real_name][H.mind.assigned_role]")
L.fields["name"] = H.real_name
- L.fields["rank"] = H.mind.assigned_role
+ L.fields["rank"] = H.mind.assigned_role
L.fields["age"] = H.age
L.fields["sex"] = H.gender
L.fields["b_type"] = H.b_type
L.fields["b_dna"] = H.dna.unique_enzymes
- L.fields["enzymes"] = H.dna.struc_enzymes
- L.fields["identity"] = H.dna.uni_identity
+ L.fields["enzymes"] = H.dna.SE // Used in respawning
+ L.fields["identity"] = H.dna.UI // "
L.fields["image"] = getFlatIcon(H,0) //This is god-awful
locked += L
return
diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm
index dc3a3b36dbd..c335a6f1fac 100644
--- a/code/datums/datumvars.dm
+++ b/code/datums/datumvars.dm
@@ -258,6 +258,9 @@ client
body += ""
body += ""
body += ""
+
+ body += ""
+ body += ""
if(ishuman(D))
body += ""
body += ""
@@ -808,6 +811,55 @@ client
else
usr << "Mob doesn't know that language."
+ else if(href_list["addverb"])
+ if(!check_rights(R_DEBUG)) return
+
+ var/mob/living/H = locate(href_list["addverb"])
+
+ if(!istype(H))
+ usr << "This can only be done to instances of type /mob/living"
+ return
+ var/list/possibleverbs = list()
+ possibleverbs += "Cancel" // One for the top...
+ possibleverbs += typesof(/mob/proc,/mob/verb,/mob/living/proc,/mob/living/verb)
+ switch(H.type)
+ if(/mob/living/carbon/human)
+ possibleverbs += typesof(/mob/living/carbon/proc,/mob/living/carbon/verb,/mob/living/carbon/human/verb,/mob/living/carbon/human/proc)
+ if(/mob/living/silicon/robot)
+ possibleverbs += typesof(/mob/living/silicon/proc,/mob/living/silicon/robot/proc,/mob/living/silicon/robot/verb)
+ if(/mob/living/silicon/ai)
+ possibleverbs += typesof(/mob/living/silicon/proc,/mob/living/silicon/ai/proc,/mob/living/silicon/ai/verb)
+ possibleverbs -= H.verbs
+ possibleverbs += "Cancel" // ...And one for the bottom
+
+ var/verb = input("Select a verb!", "Verbs",null) as anything in possibleverbs
+ if(!H)
+ usr << "Mob doesn't exist anymore"
+ return
+ if(!verb || verb == "Cancel")
+ return
+ else
+ H.verbs += verb
+
+ else if(href_list["remverb"])
+ if(!check_rights(R_DEBUG)) return
+
+ var/mob/H = locate(href_list["remverb"])
+
+ if(!istype(H))
+ usr << "This can only be done to instances of type /mob"
+ return
+ var/verb = input("Please choose a verb to remove.","Verbs",null) as null|anything in H.verbs
+ if(!H)
+ usr << "Mob doesn't exist anymore"
+ return
+ if(!verb)
+ return
+ else
+ H.verbs -= verb
+
+
+
else if(href_list["regenerateicons"])
if(!check_rights(0)) return
diff --git a/code/datums/diseases/advance/advance.dm b/code/datums/diseases/advance/advance.dm
index 95adc92dcc3..376df936782 100644
--- a/code/datums/diseases/advance/advance.dm
+++ b/code/datums/diseases/advance/advance.dm
@@ -297,7 +297,7 @@ var/list/advance_cures = list(
for(var/datum/symptom/S in symptoms)
L += S.id
L = sortList(L) // Sort the list so it doesn't matter which order the symptoms are in.
- var/result = dd_list2text(L, ":")
+ var/result = list2text(L, ":")
id = result
return result
diff --git a/code/datums/diseases/appendicitis.dm b/code/datums/diseases/appendicitis.dm
index 16b4008fef0..502ce1e7346 100644
--- a/code/datums/diseases/appendicitis.dm
+++ b/code/datums/diseases/appendicitis.dm
@@ -45,7 +45,7 @@
H.op_stage.appendix = 2.0
var/datum/organ/external/groin = H.get_organ("groin")
- var/datum/wound/W = new /datum/wound/internal_bleeding(25)
+ var/datum/wound/W = new /datum/wound/internal_bleeding(20)
H.adjustToxLoss(25)
groin.wounds += W
src.cure()
diff --git a/code/datums/diseases/dna_spread.dm b/code/datums/diseases/dna_spread.dm
index c7c5f812122..69a8eb6500f 100644
--- a/code/datums/diseases/dna_spread.dm
+++ b/code/datums/diseases/dna_spread.dm
@@ -39,13 +39,13 @@
//Save original dna for when the disease is cured.
src.original_dna["name"] = affected_mob.real_name
- src.original_dna["UI"] = affected_mob.dna.uni_identity
- src.original_dna["SE"] = affected_mob.dna.struc_enzymes
+ src.original_dna["UI"] = affected_mob.dna.UI
+ src.original_dna["SE"] = affected_mob.dna.SE
affected_mob << "\red You don't feel like yourself.."
- affected_mob.dna.uni_identity = strain_data["UI"]
- updateappearance(affected_mob, affected_mob.dna.uni_identity)
- affected_mob.dna.struc_enzymes = strain_data["SE"]
+ affected_mob.UpdateAppearance(strain_data["UI"])
+ affected_mob.dna.SE = strain_data["SE"]
+ affected_mob.dna.UpdateSE()
affected_mob.real_name = strain_data["name"]
domutcheck(affected_mob)
@@ -56,9 +56,9 @@
/datum/disease/dnaspread/Del()
if ((original_dna["name"]) && (original_dna["UI"]) && (original_dna["SE"]))
- affected_mob.dna.uni_identity = original_dna["UI"]
- updateappearance(affected_mob, affected_mob.dna.uni_identity)
- affected_mob.dna.struc_enzymes = original_dna["SE"]
+ affected_mob.UpdateAppearance(original_dna["UI"])
+ affected_mob.dna.SE = original_dna["SE"]
+ affected_mob.dna.UpdateSE()
affected_mob.real_name = original_dna["name"]
affected_mob << "\blue You feel more like yourself."
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 500008d2f6f..d85c1a61f1a 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -74,6 +74,8 @@ datum/mind
current.mind = null
if(new_character.mind) //remove any mind currently in our new body's mind variable
new_character.mind.current = null
+
+ nanomanager.user_transferred(current, new_character) // transfer active NanoUI instances to new user
current = new_character //link ourself to our new body
new_character.mind = src //and link our new body to ourself
@@ -550,6 +552,7 @@ datum/mind
current << "\red You have been brainwashed! You are no longer a head revolutionary!"
ticker.mode.update_rev_icons_removed(src)
special_role = null
+ current.verbs -= /mob/living/carbon/human/proc/RevConvert
log_admin("[key_name_admin(usr)] has de-rev'ed [current].")
if("rev")
@@ -570,7 +573,7 @@ datum/mind
if(src in ticker.mode.revolutionaries)
ticker.mode.revolutionaries -= src
ticker.mode.update_rev_icons_removed(src)
- current << "\red You have proved your devotion to revoltion! Yea are a head revolutionary now!"
+ current << "\red You have proved your devotion to revoltion! You are a head revolutionary now!"
else if(!(src in ticker.mode.head_revolutionaries))
current << "\blue You are a member of the revolutionaries' leadership now!"
else
@@ -586,6 +589,7 @@ datum/mind
rev_obj.explanation_text = "Assassinate [O.target.name], the [O.target.assigned_role]."
objectives += rev_obj
ticker.mode.greet_revolutionary(src,0)
+ current.verbs += /mob/living/carbon/human/proc/RevConvert
ticker.mode.head_revolutionaries += src
ticker.mode.update_rev_icons_added(src)
special_role = "Head Revolutionary"
@@ -726,7 +730,7 @@ datum/mind
else
current.dna = changeling.absorbed_dna[1]
current.real_name = current.dna.real_name
- updateappearance(current, current.dna.uni_identity)
+ current.UpdateAppearance()
domutcheck(current, null)
else if (href_list["nuclear"])
diff --git a/code/datums/spell.dm b/code/datums/spell.dm
index 75f2d5f3e5f..346ba7ce299 100644
--- a/code/datums/spell.dm
+++ b/code/datums/spell.dm
@@ -173,11 +173,11 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin
sparks.start()
if(smoke_spread)
if(smoke_spread == 1)
- var/datum/effect/effect/system/harmless_smoke_spread/smoke = new /datum/effect/effect/system/harmless_smoke_spread()
+ var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread()
smoke.set_up(smoke_amt, 0, location) //no idea what the 0 is
smoke.start()
else if(smoke_spread == 2)
- var/datum/effect/effect/system/bad_smoke_spread/smoke = new /datum/effect/effect/system/bad_smoke_spread()
+ var/datum/effect/effect/system/smoke_spread/bad/smoke = new /datum/effect/effect/system/smoke_spread/bad()
smoke.set_up(smoke_amt, 0, location) //no idea what the 0 is
smoke.start()
diff --git a/code/datums/sun.dm b/code/datums/sun.dm
index 9ce8a73cb72..82acfa0cff0 100644
--- a/code/datums/sun.dm
+++ b/code/datums/sun.dm
@@ -14,6 +14,10 @@
if(prob(50))
rate = -rate
+/hook/startup/proc/createSun()
+ sun = new /datum/sun()
+ return 1
+
// calculate the sun's position given the time of day
/datum/sun/proc/calc_position()
diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm
index 297bdb890da..e3cc43642d9 100755
--- a/code/datums/supplypacks.dm
+++ b/code/datums/supplypacks.dm
@@ -128,12 +128,12 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
/obj/item/weapon/reagent_containers/food/drinks/bottle/goldschlager,
/obj/item/weapon/storage/fancy/cigarettes/dromedaryco,
/obj/item/weapon/lipstick/random,
- /obj/item/weapon/reagent_containers/food/drinks/ale,
- /obj/item/weapon/reagent_containers/food/drinks/ale,
- /obj/item/weapon/reagent_containers/food/drinks/beer,
- /obj/item/weapon/reagent_containers/food/drinks/beer,
- /obj/item/weapon/reagent_containers/food/drinks/beer,
- /obj/item/weapon/reagent_containers/food/drinks/beer)
+ /obj/item/weapon/reagent_containers/food/drinks/cans/ale,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/ale,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/beer,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/beer,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/beer,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/beer)
cost = 20
containertype = /obj/structure/closet/crate
containername = "Party equipment"
@@ -456,6 +456,14 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
containername = "fuel tank crate"
group = "Engineering"
+/datum/supply_packs/coolanttank
+ name = "Coolant tank crate"
+ contains = list(/obj/structure/reagent_dispensers/coolanttank)
+ cost = 16
+ containertype = /obj/structure/largecrate
+ containername = "coolant tank crate"
+ group = "Medical / Science"
+
/datum/supply_packs/solar
name = "Solar Pack crate"
contains = list(/obj/item/solar_assembly,
@@ -687,6 +695,18 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
access = access_armory
group = "Security"
+/datum/supply_packs/erifle
+ name = "Energy marksman crate"
+ contains = list(/obj/item/clothing/suit/armor/laserproof,
+ /obj/item/clothing/suit/armor/laserproof,
+ /obj/item/weapon/gun/energy/sniperrifle,
+ /obj/item/weapon/gun/energy/sniperrifle)
+ cost = 50
+ containertype = /obj/structure/closet/crate/secure
+ containername = "Energy marksman crate"
+ access = access_armory
+ group = "Security"
+
/datum/supply_packs/shotgunammo
name = "Shotgun shells"
contains = list(/obj/item/ammo_casing/shotgun,
@@ -945,6 +965,25 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
group = "Engineering"
access = access_ce
+/datum/supply_packs/smbig
+ name = "Supermatter Core"
+ contains = list(/obj/machinery/power/supermatter)
+ cost = 50
+ containertype = /obj/structure/closet/crate/secure/plasma
+ containername = "Supermatter crate (CAUTION)"
+ group = "Engineering"
+ access = access_ce
+
+
+/* /datum/supply_packs/smsmall // Currently nonfunctional, waiting on virgil
+ name = "Supermatter Shard"
+ contains = list(/obj/machinery/power/supermatter/shard)
+ cost = 25
+ containertype = /obj/structure/closet/crate/secure/plasma
+ containername = "Supermatter shard crate (CAUTION)"
+ access = access_ce
+ group = "Engineering" */
+
/datum/supply_packs/shield_cap
contains = list(/obj/item/weapon/circuitboard/shield_cap)
name = "Experimental shield capacitor circuitry"
diff --git a/code/defines/obj.dm b/code/defines/obj.dm
index 6c6269d301e..e6a4a7a4cb5 100644
--- a/code/defines/obj.dm
+++ b/code/defines/obj.dm
@@ -51,122 +51,194 @@
//This list tracks characters spawned in the world and cannot be modified in-game. Currently referenced by respawn_character().
var/locked[] = list()
- proc/get_manifest(monochrome, OOC)
- var/list/heads = new()
- var/list/sec = new()
- var/list/eng = new()
- var/list/med = new()
- var/list/sci = new()
- var/list/civ = new()
- var/list/bot = new()
- var/list/misc = new()
- var/list/isactive = new()
- var/dat = {"
-
-
+ "}
+ var/even = 0
+ // sort mobs
+ for(var/datum/data/record/t in data_core.general)
+ var/name = t.fields["name"]
+ var/rank = t.fields["rank"]
+ var/real_rank = t.fields["real_rank"]
+ if(OOC)
+ var/active = 0
+ for(var/mob/M in player_list)
+ if(M.real_name == name && M.client && M.client.inactivity <= 10 * 60 * 10)
+ active = 1
+ break
+ isactive[name] = active ? "Active" : "Inactive"
+ else
+ isactive[name] = t.fields["p_stat"]
//world << "[name]: [rank]"
-
//cael - to prevent multiple appearances of a player/job combination, add a continue after each line
- var/department = 0
- if(real_rank in command_positions)
- heads[name] = rank
- department = 1
- if(real_rank in security_positions)
- sec[name] = rank
- department = 1
- if(real_rank in engineering_positions)
- eng[name] = rank
- department = 1
- if(real_rank in medical_positions)
- med[name] = rank
- department = 1
- if(real_rank in science_positions)
- sci[name] = rank
- department = 1
- if(real_rank in civilian_positions)
- civ[name] = rank
- department = 1
- if(real_rank in nonhuman_positions)
- bot[name] = rank
- department = 1
+ var/department = 0
+ if(real_rank in command_positions)
+ heads[name] = rank
+ department = 1
+ if(real_rank in security_positions)
+ sec[name] = rank
+ department = 1
+ if(real_rank in engineering_positions)
+ eng[name] = rank
+ department = 1
+ if(real_rank in medical_positions)
+ med[name] = rank
+ department = 1
+ if(real_rank in science_positions)
+ sci[name] = rank
+ department = 1
+ if(real_rank in civilian_positions)
+ civ[name] = rank
+ department = 1
+ if(real_rank in nonhuman_positions)
+ bot[name] = rank
+ department = 1
+ if(!department && !(name in heads))
+ misc[name] = rank
+ if(heads.len > 0)
+ dat += "
Heads
"
+ for(name in heads)
+ dat += "
[name]
[heads[name]]
[isactive[name]]
"
+ even = !even
+ if(sec.len > 0)
+ dat += "
Security
"
+ for(name in sec)
+ dat += "
[name]
[sec[name]]
[isactive[name]]
"
+ even = !even
+ if(eng.len > 0)
+ dat += "
Engineering
"
+ for(name in eng)
+ dat += "
[name]
[eng[name]]
[isactive[name]]
"
+ even = !even
+ if(med.len > 0)
+ dat += "
Medical
"
+ for(name in med)
+ dat += "
[name]
[med[name]]
[isactive[name]]
"
+ even = !even
+ if(sci.len > 0)
+ dat += "
Science
"
+ for(name in sci)
+ dat += "
[name]
[sci[name]]
[isactive[name]]
"
+ even = !even
+ if(civ.len > 0)
+ dat += "
Civilian
"
+ for(name in civ)
+ dat += "
[name]
[civ[name]]
[isactive[name]]
"
+ even = !even
+ // in case somebody is insane and added them to the manifest, why not
+ if(bot.len > 0)
+ dat += "
Silicon
"
+ for(name in bot)
+ dat += "
[name]
[bot[name]]
[isactive[name]]
"
+ even = !even
+ // misc guys
+ if(misc.len > 0)
+ dat += "
Miscellaneous
"
+ for(name in misc)
+ dat += "
[name]
[misc[name]]
[isactive[name]]
"
+ even = !even
- if(!department && !(name in heads))
- misc[name] = rank
-
- if(heads.len > 0)
- dat += "
Heads
"
- for(name in heads)
- dat += "
[name]
[heads[name]]
[isactive[name]]
"
- even = !even
- if(sec.len > 0)
- dat += "
Security
"
- for(name in sec)
- dat += "
[name]
[sec[name]]
[isactive[name]]
"
- even = !even
- if(eng.len > 0)
- dat += "
Engineering
"
- for(name in eng)
- dat += "
[name]
[eng[name]]
[isactive[name]]
"
- even = !even
- if(med.len > 0)
- dat += "
Medical
"
- for(name in med)
- dat += "
[name]
[med[name]]
[isactive[name]]
"
- even = !even
- if(sci.len > 0)
- dat += "
Science
"
- for(name in sci)
- dat += "
[name]
[sci[name]]
[isactive[name]]
"
- even = !even
- if(civ.len > 0)
- dat += "
Civilian
"
- for(name in civ)
- dat += "
[name]
[civ[name]]
[isactive[name]]
"
- even = !even
- // in case somebody is insane and added them to the manifest, why not
- if(bot.len > 0)
- dat += "
Silicon
"
- for(name in bot)
- dat += "
[name]
[bot[name]]
[isactive[name]]
"
- even = !even
- // misc guys
- if(misc.len > 0)
- dat += "
Miscellaneous
"
- for(name in misc)
- dat += "
[name]
[misc[name]]
[isactive[name]]
"
- even = !even
+ dat += "
"
+ dat = replacetext(dat, "\n", "") // so it can be placed on paper correctly
+ dat = replacetext(dat, "\t", "")
+ return dat
+
+
+/*
+We can't just insert in HTML into the nanoUI so we need the raw data to play with.
+*/
+
+/obj/effect/datacore/proc/get_manifest_json()
+ var/heads[0]
+ var/sec[0]
+ var/eng[0]
+ var/med[0]
+ var/sci[0]
+ var/civ[0]
+ var/bot[0]
+ var/misc[0]
+ for(var/datum/data/record/t in data_core.general)
+ var/name = sanitize(t.fields["name"])
+ var/rank = sanitize(t.fields["rank"])
+ var/real_rank = t.fields["real_rank"]
+ var/isactive = t.fields["p_stat"]
+ var/department = 0
+ var/depthead = 0 // Department Heads will be placed at the top of their lists.
+ if(real_rank in command_positions)
+ heads[++heads.len] = list("name" = name, "rank" = rank, "active" = isactive)
+ department = 1
+ depthead = 1
+ if(rank=="Captain" && heads.len != 1)
+ heads.Swap(1,heads.len)
+
+ if(real_rank in security_positions)
+ sec[++sec.len] = list("name" = name, "rank" = rank, "active" = isactive)
+ department = 1
+ if(depthead && sec.len != 1)
+ sec.Swap(1,sec.len)
+
+ if(real_rank in engineering_positions)
+ eng[++eng.len] = list("name" = name, "rank" = rank, "active" = isactive)
+ department = 1
+ if(depthead && eng.len != 1)
+ eng.Swap(1,eng.len)
+
+ if(real_rank in medical_positions)
+ med[++med.len] = list("name" = name, "rank" = rank, "active" = isactive)
+ department = 1
+ if(depthead && med.len != 1)
+ med.Swap(1,med.len)
+
+ if(real_rank in science_positions)
+ sci[++sci.len] = list("name" = name, "rank" = rank, "active" = isactive)
+ department = 1
+ if(depthead && sci.len != 1)
+ sci.Swap(1,sci.len)
+
+ if(real_rank in civilian_positions)
+ civ[++civ.len] = list("name" = name, "rank" = rank, "active" = isactive)
+ department = 1
+ if(depthead && civ.len != 1)
+ civ.Swap(1,civ.len)
+
+ if(real_rank in nonhuman_positions)
+ bot[++bot.len] = list("name" = name, "rank" = rank, "active" = isactive)
+ department = 1
+
+ if(!department && !(name in heads))
+ misc[++misc.len] = list("name" = name, "rank" = rank, "active" = isactive)
+
+ return list(\
+ "heads" = heads,\
+ "sec" = sec,\
+ "eng" = eng,\
+ "med" = med,\
+ "sci" = sci,\
+ "civ" = civ,\
+ "bot" = bot,\
+ "misc" = misc\
+ )
- dat += "
"
- dat = replacetext(dat, "\n", "") // so it can be placed on paper correctly
- dat = replacetext(dat, "\t", "")
- return dat
/obj/effect/laser
name = "laser"
diff --git a/code/defines/obj/hydro.dm b/code/defines/obj/hydro.dm
index 7cb2439cc68..2b57dbeffa5 100644
--- a/code/defines/obj/hydro.dm
+++ b/code/defines/obj/hydro.dm
@@ -132,6 +132,40 @@
plant_type = 0
growthstages = 1
+/obj/item/seeds/shandseed
+ name = "pack of s'rendarr's hand seeds"
+ desc = "These seeds grow into a helpful herb called S'Rendarr's Hand, native to Ahdomai."
+ icon_state = "seed-shand"
+ mypath = "/obj/item/seeds/shandseed"
+ species = "shand"
+ plantname = "S'Rendarr's Hand"
+ productname = "/obj/item/stack/medical/bruise_pack/tajaran"
+ lifespan = 50
+ endurance = 25
+ maturation = 3
+ production = 5
+ yield = 4
+ potency = 10
+ plant_type = 0
+ growthstages = 3
+
+/obj/item/seeds/mtearseed
+ name = "pack of messa's tear seeds"
+ desc = "These seeds grow into a helpful herb called Messa's Tear, native to Ahdomai."
+ icon_state = "seed-mtear"
+ mypath = "/obj/item/seeds/mtearseed"
+ species = "mtear"
+ plantname = "Messa's Tear"
+ productname = "/obj/item/stack/medical/ointment/tajaran"
+ lifespan = 50
+ endurance = 25
+ maturation = 3
+ production = 5
+ yield = 4
+ potency = 10
+ plant_type = 0
+ growthstages = 3
+
/obj/item/seeds/berryseed
name = "pack of berry seeds"
desc = "These seeds grow into berry bushes."
diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm
index b84388f5838..4e7beba1ddc 100644
--- a/code/defines/obj/weapon.dm
+++ b/code/defines/obj/weapon.dm
@@ -325,6 +325,13 @@
icon = 'icons/obj/wizard.dmi'
icon_state = "broom"
+/obj/item/weapon/staff/gentcane
+ name = "Gentlemans Cane"
+ desc = "An ebony can with an ivory tip."
+ icon = 'icons/obj/weapons.dmi'
+ icon_state = "cane"
+ item_state = "stick"
+
/obj/item/weapon/staff/stick
name = "stick"
desc = "A great tool to drag someone else's drinks across the bar."
@@ -393,7 +400,9 @@
/obj/item/weapon/module/power_control
name = "power control module"
icon_state = "power_mod"
- desc = "Heavy-duty switching circuits for power control."
+ desc = "Heavy-duty switching circuits for power control."
+ m_amt = 50
+ g_amt = 50
/obj/item/weapon/module/id_auth
name = "\improper ID authentication module"
diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm
index 9133753e4ee..9c04d5b672d 100755
--- a/code/game/area/Space Station 13 areas.dm
+++ b/code/game/area/Space Station 13 areas.dm
@@ -56,7 +56,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
/*I am far too lazy to make it a proper list of areas so I'll just make it run the usual telepot routine at the start of the game*/
var/list/teleportlocs = list()
-proc/process_teleport_locs()
+/hook/startup/proc/setupTeleportLocs()
for(var/area/AR in world)
if(istype(AR, /area/shuttle) || istype(AR, /area/syndicate_station) || istype(AR, /area/wizard_station)) continue
if(teleportlocs.Find(AR.name)) continue
@@ -65,20 +65,13 @@ proc/process_teleport_locs()
teleportlocs += AR.name
teleportlocs[AR.name] = AR
- var/not_in_order = 0
- do
- not_in_order = 0
- if(teleportlocs.len <= 1)
- break
- for(var/i = 1, i <= (teleportlocs.len - 1), i++)
- if(sorttext(teleportlocs[i], teleportlocs[i+1]) == -1)
- teleportlocs.Swap(i, i+1)
- not_in_order = 1
- while(not_in_order)
+ teleportlocs = sortAssoc(teleportlocs)
+
+ return 1
var/list/ghostteleportlocs = list()
-proc/process_ghost_teleport_locs()
+/hook/startup/proc/setupGhostTeleportLocs()
for(var/area/AR in world)
if(ghostteleportlocs.Find(AR.name)) continue
if(istype(AR, /area/turret_protected/aisat) || istype(AR, /area/derelict) || istype(AR, /area/tdome))
@@ -89,17 +82,9 @@ proc/process_ghost_teleport_locs()
ghostteleportlocs += AR.name
ghostteleportlocs[AR.name] = AR
- var/not_in_order = 0
- do
- not_in_order = 0
- if(ghostteleportlocs.len <= 1)
- break
- for(var/i = 1, i <= (ghostteleportlocs.len - 1), i++)
- if(sorttext(ghostteleportlocs[i], ghostteleportlocs[i+1]) == -1)
- ghostteleportlocs.Swap(i, i+1)
- not_in_order = 1
- while(not_in_order)
+ ghostteleportlocs = sortAssoc(ghostteleportlocs)
+ return 1
/*-----------------------------------------------------------------------------*/
@@ -795,6 +780,14 @@ proc/process_ghost_teleport_locs()
name = "\improper Dormitories"
icon_state = "Sleep"
+/area/crew_quarters/sleep/engi
+ name = "\improper Engineering Dormitories"
+ icon_state = "Sleep"
+
+/area/crew_quarters/sleep/sec
+ name = "\improper Security Dormitories"
+ icon_state = "Sleep"
+
/area/crew_quarters/sleep_male
name = "\improper Male Dorm"
icon_state = "Sleep"
@@ -1322,6 +1315,10 @@ proc/process_ghost_teleport_locs()
name = "\improper Miscellaneous Research"
icon_state = "toxmisc"
+/area/toxins/telesci
+ name = "\improper Telescience Lab"
+ icon_state = "toxmisc"
+
/area/toxins/server
name = "\improper Server Room"
icon_state = "server"
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index 6695fe44027..f69b2a35e3f 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -100,6 +100,7 @@
return
if( !fire )
fire = 1
+ master.fire = 1 //used for firedoor checks
updateicon()
mouse_opacity = 0
for(var/obj/machinery/door/firedoor/D in all_doors)
@@ -122,6 +123,7 @@
/area/proc/firereset()
if (fire)
fire = 0
+ master.fire = 0 //used for firedoor checks
mouse_opacity = 0
updateicon()
for(var/obj/machinery/door/firedoor/D in all_doors)
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index f5870a24998..109a95fe729 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -6,6 +6,7 @@
var/list/fingerprintshidden
var/fingerprintslast = null
var/list/blood_DNA
+ var/blood_color
var/last_bumped = 0
var/pass_flags = 0
var/throwpass = 0
@@ -361,7 +362,9 @@ its easier to just keep the beam vertical.
return 0
if(!blood_DNA || !istype(blood_DNA, /list)) //if our list of DNA doesn't exist yet (or isn't a list) initialise it.
blood_DNA = list()
-
+ blood_color = "#A10808"
+ if (M.species)
+ blood_color = M.species.blood_color
//adding blood to humans
else if (istype(src, /mob/living/carbon/human))
var/mob/living/carbon/human/H = src
diff --git a/code/game/communications.dm b/code/game/communications.dm
index 32d8ca69348..4f13277a31d 100644
--- a/code/game/communications.dm
+++ b/code/game/communications.dm
@@ -103,16 +103,16 @@ var/list/radiochannels = list(
"Medical" = 1355,
"Engineering" = 1357,
"Security" = 1359,
- "Response Team" = 1443,
- "Deathsquad" = 1441,
+ "Response Team" = 1345,
+ "Deathsquad" = 1341,
"Syndicate" = 1213,
"Supply" = 1347,
)
//depenging helpers
-var/list/DEPT_FREQS = list(1351, 1355, 1357, 1359, 1213, 1443, 1441, 1347)
+var/list/DEPT_FREQS = list(1351, 1355, 1357, 1359, 1213, 1345, 1341, 1347)
// central command channels, i.e deathsquid & response teams
-var/list/CENT_FREQS = list(1441, 1443)
+var/list/CENT_FREQS = list(1345, 1341)
var/const/COMM_FREQ = 1353 //command, colored gold in chat window
var/const/SYND_FREQ = 1213
@@ -140,6 +140,10 @@ var/const/RADIO_MAGNETS = "9"
var/global/datum/controller/radio/radio_controller
+/hook/startup/proc/createRadioController()
+ radio_controller = new /datum/controller/radio()
+ return 1
+
datum/controller/radio
var/list/datum/radio_frequency/frequencies = list()
diff --git a/code/game/dna/dna2.dm b/code/game/dna/dna2.dm
new file mode 100644
index 00000000000..e8f4ddc4a8b
--- /dev/null
+++ b/code/game/dna/dna2.dm
@@ -0,0 +1,358 @@
+/**
+* DNA 2: The Spaghetti Strikes Back
+*
+* @author N3X15
+*/
+
+// What each index means:
+#define DNA_OFF_LOWERBOUND 0
+#define DNA_OFF_UPPERBOUND 1
+#define DNA_ON_LOWERBOUND 2
+#define DNA_ON_UPPERBOUND 3
+
+// Define block bounds (off-low,off-high,on-low,on-high)
+// Used in setupgame.dm
+#define DNA_DEFAULT_BOUNDS list(1,2049,2050,4095)
+#define DNA_HARDER_BOUNDS list(1,3049,3050,4095)
+#define DNA_HARD_BOUNDS list(1,3490,3500,4095)
+
+// Defines which values mean "on" or "off".
+// This is to make some of the more OP superpowers a larger PITA to activate,
+// and to tell our new DNA datum which values to set in order to turn something
+// on or off.
+var/global/list/dna_activity_bounds[STRUCDNASIZE]
+
+// Used to determine what each block means (admin hax and species stuff on /vg/, mostly)
+var/global/list/assigned_blocks[STRUCDNASIZE]
+
+var/global/list/datum/dna/gene/dna_genes[0]
+
+// UI Indices (can change to mutblock style, if desired)
+#define DNA_UI_HAIR_R 1
+#define DNA_UI_HAIR_G 2
+#define DNA_UI_HAIR_B 3
+#define DNA_UI_BEARD_R 4
+#define DNA_UI_BEARD_G 5
+#define DNA_UI_BEARD_B 6
+#define DNA_UI_SKIN_TONE 7
+#define DNA_UI_EYES_R 8
+#define DNA_UI_EYES_G 9
+#define DNA_UI_EYES_B 10
+#define DNA_UI_GENDER 11
+#define DNA_UI_BEARD_STYLE 12
+#define DNA_UI_HAIR_STYLE 13
+#define DNA_UI_LENGTH 13 // Update this when you add something, or you WILL break shit.
+
+/////////////////
+// GENE DEFINES
+/////////////////
+
+// Skip checking if it's already active.
+// Used for genes that check for value rather than a binary on/off.
+#define GENE_ALWAYS_ACTIVATE 1
+
+/datum/dna
+ // READ-ONLY, GETS OVERWRITTEN
+ // DO NOT FUCK WITH THESE OR BYOND WILL EAT YOUR FACE
+ var/uni_identity="" // Encoded UI
+ var/struc_enzymes="" // Encoded SE
+ var/unique_enzymes="" // MD5 of player name
+
+ // Internal dirtiness checks
+ var/dirtyUI=0
+ var/dirtySE=0
+
+ // Okay to read, but you're an idiot if you do.
+ // BLOCK = VALUE
+ var/list/SE[STRUCDNASIZE]
+ var/list/UI[DNA_UI_LENGTH]
+
+ // From old dna.
+ var/b_type = "A+" // Should probably change to an integer => string map but I'm lazy.
+ var/mutantrace = null // The type of mutant race the player is, if applicable (i.e. potato-man)
+ var/real_name // Stores the real name of the person who originally got this dna datum. Used primarily for changelings,
+
+ // New stuff
+ var/species = "Human"
+
+// Make a copy of this strand.
+// USE THIS WHEN COPYING STUFF OR YOU'LL GET CORRUPTION!
+/datum/dna/proc/Clone()
+ var/datum/dna/new_dna = new()
+ new_dna.unique_enzymes=unique_enzymes
+ new_dna.b_type=b_type
+ new_dna.mutantrace=mutantrace
+ new_dna.real_name=real_name
+ new_dna.species=species
+ for(var/b=1;b<=STRUCDNASIZE;b++)
+ new_dna.SE[b]=SE[b]
+ if(b<=DNA_UI_LENGTH)
+ new_dna.UI[b]=UI[b]
+ new_dna.UpdateUI()
+ new_dna.UpdateSE()
+ return new_dna
+
+///////////////////////////////////////
+// UNIQUE IDENTITY
+///////////////////////////////////////
+
+// Create random UI.
+/datum/dna/proc/ResetUI(var/defer=0)
+ for(var/i=1,i<=DNA_UI_LENGTH,i++)
+ switch(i)
+ if(DNA_UI_SKIN_TONE)
+ SetUIValueRange(DNA_UI_SKIN_TONE,rand(1,220),220,1) // Otherwise, it gets fucked
+ else
+ UI[i]=rand(0,4095)
+ if(!defer)
+ UpdateUI()
+
+/datum/dna/proc/ResetUIFrom(var/mob/living/carbon/human/character)
+ // INITIALIZE!
+ ResetUI(1)
+ // Hair
+ // FIXME: Species-specific defaults pls
+ if(!character.h_style)
+ character.h_style = "Skinhead"
+ var/hair = hair_styles_list.Find(character.h_style)
+
+ // Facial Hair
+ if(!character.f_style)
+ character.f_style = "Shaved"
+ var/beard = facial_hair_styles_list.Find(character.f_style)
+
+ SetUIValueRange(DNA_UI_HAIR_R, character.r_hair, 255, 1)
+ SetUIValueRange(DNA_UI_HAIR_G, character.g_hair, 255, 1)
+ SetUIValueRange(DNA_UI_HAIR_B, character.b_hair, 255, 1)
+
+ SetUIValueRange(DNA_UI_BEARD_R, character.r_facial, 255, 1)
+ SetUIValueRange(DNA_UI_BEARD_G, character.g_facial, 255, 1)
+ SetUIValueRange(DNA_UI_BEARD_B, character.b_facial, 255, 1)
+
+ SetUIValueRange(DNA_UI_EYES_R, character.r_eyes, 255, 1)
+ SetUIValueRange(DNA_UI_EYES_G, character.g_eyes, 255, 1)
+ SetUIValueRange(DNA_UI_EYES_B, character.b_eyes, 255, 1)
+
+ SetUIValueRange(DNA_UI_SKIN_TONE, 35-character.s_tone, 220, 1) // Value can be negative.
+
+ SetUIState(DNA_UI_GENDER, character.gender!=MALE, 1)
+
+ SetUIValueRange(DNA_UI_HAIR_STYLE, hair, hair_styles_list.len, 1)
+ SetUIValueRange(DNA_UI_BEARD_STYLE, beard, facial_hair_styles_list.len,1)
+
+ UpdateUI()
+
+// Set a DNA UI block's raw value.
+/datum/dna/proc/SetUIValue(var/block,var/value,var/defer=0)
+ if (block<=0) return
+ ASSERT(value>=0)
+ ASSERT(value<=4095)
+ UI[block]=value
+ dirtyUI=1
+ if(!defer)
+ UpdateUI()
+
+// Get a DNA UI block's raw value.
+/datum/dna/proc/GetUIValue(var/block)
+ if (block<=0) return 0
+ return UI[block]
+
+// Set a DNA UI block's value, given a value and a max possible value.
+// Used in hair and facial styles (value being the index and maxvalue being the len of the hairstyle list)
+/datum/dna/proc/SetUIValueRange(var/block,var/value,var/maxvalue,var/defer=0)
+ if (block<=0) return
+ ASSERT(maxvalue<=4095)
+ var/range = (4095 / maxvalue)
+ if(value)
+ SetUIValue(block,round(value * range),defer)
+
+// Getter version of above.
+/datum/dna/proc/GetUIValueRange(var/block,var/maxvalue)
+ if (block<=0) return 0
+ var/value = GetUIValue(block)
+ return round(1 +(value / 4096)*maxvalue)
+
+// Is the UI gene "on" or "off"?
+// For UI, this is simply a check of if the value is > 2050.
+/datum/dna/proc/GetUIState(var/block)
+ if (block<=0) return
+ return UI[block] > 2050
+
+
+// Set UI gene "on" (1) or "off" (0)
+/datum/dna/proc/SetUIState(var/block,var/on,var/defer=0)
+ if (block<=0) return
+ var/val
+ if(on)
+ val=rand(2050,4095)
+ else
+ val=rand(1,2049)
+ SetUIValue(block,val,defer)
+
+// Get a hex-encoded UI block.
+/datum/dna/proc/GetUIBlock(var/block)
+ return EncodeDNABlock(GetUIValue(block))
+
+// Do not use this unless you absolutely have to.
+// Set a block from a hex string. This is inefficient. If you can, use SetUIValue().
+// Used in DNA modifiers.
+/datum/dna/proc/SetUIBlock(var/block,var/value,var/defer=0)
+ if (block<=0) return
+ return SetUIValue(block,hex2num(value),defer)
+
+// Get a sub-block from a block.
+/datum/dna/proc/GetUISubBlock(var/block,var/subBlock)
+ return copytext(GetUIBlock(block),subBlock,subBlock+1)
+
+// Do not use this unless you absolutely have to.
+// Set a block from a hex string. This is inefficient. If you can, use SetUIValue().
+// Used in DNA modifiers.
+/datum/dna/proc/SetUISubBlock(var/block,var/subBlock, var/newSubBlock, var/defer=0)
+ if (block<=0) return
+ var/oldBlock=GetUIBlock(block)
+ var/newBlock=""
+ for(var/i=1, i<=length(oldBlock), i++)
+ if(i==subBlock)
+ newBlock+=newSubBlock
+ else
+ newBlock+=copytext(oldBlock,i,i+1)
+ SetUIBlock(block,newBlock,defer)
+
+///////////////////////////////////////
+// STRUCTURAL ENZYMES
+///////////////////////////////////////
+
+// "Zeroes out" all of the blocks.
+/datum/dna/proc/ResetSE()
+ for(var/i = 1, i <= STRUCDNASIZE, i++)
+ SetSEValue(i,rand(1,1024),1)
+ UpdateSE()
+
+// Set a DNA SE block's raw value.
+/datum/dna/proc/SetSEValue(var/block,var/value,var/defer=0)
+ //testing("SetSEBlock([block],[value],[defer]): [value] -> [nval]")
+ if (block<=0) return
+ ASSERT(value>=0)
+ ASSERT(value<=4095)
+ SE[block]=value
+ dirtySE=1
+ if(!defer)
+ UpdateSE()
+
+// Get a DNA SE block's raw value.
+/datum/dna/proc/GetSEValue(var/block)
+ if (block<=0) return 0
+ return SE[block]
+
+// Set a DNA SE block's value, given a value and a max possible value.
+// Might be used for species?
+/datum/dna/proc/SetSEValueRange(var/block,var/value,var/maxvalue)
+ if (block<=0) return
+ ASSERT(maxvalue<=4095)
+ var/range = round(4095 / maxvalue)
+ if(value)
+ SetSEValue(block, value * range - rand(1,range-1))
+
+// Getter version of above.
+/datum/dna/proc/GetSEValueRange(var/block,var/maxvalue)
+ if (block<=0) return 0
+ var/value = GetSEValue(block)
+ return round(1 +(value / 4096)*maxvalue)
+
+// Is the block "on" (1) or "off" (0)? (Un-assigned genes are always off.)
+/datum/dna/proc/GetSEState(var/block)
+ if (block<=0) return 0
+ var/list/BOUNDS=GetDNABounds(block)
+ var/value=GetSEValue(block)
+ return (value > BOUNDS[DNA_ON_LOWERBOUND])
+
+// Set a block "on" or "off".
+/datum/dna/proc/SetSEState(var/block,var/on,var/defer=0)
+ if (block<=0) return
+ var/list/BOUNDS=GetDNABounds(block)
+ var/val
+ if(on)
+ val=rand(BOUNDS[DNA_ON_LOWERBOUND],BOUNDS[DNA_ON_UPPERBOUND])
+ else
+ val=rand(1,BOUNDS[DNA_OFF_UPPERBOUND])
+ SetSEValue(block,val,defer)
+
+// Get hex-encoded SE block.
+/datum/dna/proc/GetSEBlock(var/block)
+ return EncodeDNABlock(GetSEValue(block))
+
+// Do not use this unless you absolutely have to.
+// Set a block from a hex string. This is inefficient. If you can, use SetUIValue().
+// Used in DNA modifiers.
+/datum/dna/proc/SetSEBlock(var/block,var/value,var/defer=0)
+ if (block<=0) return
+ var/nval=hex2num(value)
+ //testing("SetSEBlock([block],[value],[defer]): [value] -> [nval]")
+ return SetSEValue(block,nval,defer)
+
+/datum/dna/proc/GetSESubBlock(var/block,var/subBlock)
+ return copytext(GetSEBlock(block),subBlock,subBlock+1)
+
+// Do not use this unless you absolutely have to.
+// Set a sub-block from a hex character. This is inefficient. If you can, use SetUIValue().
+// Used in DNA modifiers.
+/datum/dna/proc/SetSESubBlock(var/block,var/subBlock, var/newSubBlock, var/defer=0)
+ if (block<=0) return
+ var/oldBlock=GetSEBlock(block)
+ var/newBlock=""
+ for(var/i=1, i<=length(oldBlock), i++)
+ if(i==subBlock)
+ newBlock+=newSubBlock
+ else
+ newBlock+=copytext(oldBlock,i,i+1)
+ //testing("SetSESubBlock([block],[subBlock],[newSubBlock],[defer]): [oldBlock] -> [newBlock]")
+ SetSEBlock(block,newBlock,defer)
+
+
+/proc/EncodeDNABlock(var/value)
+ return add_zero2(num2hex(value,1), 3)
+
+/datum/dna/proc/UpdateUI()
+ src.uni_identity=""
+ for(var/block in UI)
+ uni_identity += EncodeDNABlock(block)
+ //testing("New UI: [uni_identity]")
+ dirtyUI=0
+
+/datum/dna/proc/UpdateSE()
+ //var/oldse=struc_enzymes
+ struc_enzymes=""
+ for(var/block in SE)
+ struc_enzymes += EncodeDNABlock(block)
+ //testing("Old SE: [oldse]")
+ //testing("New SE: [struc_enzymes]")
+ dirtySE=0
+
+// BACK-COMPAT!
+// Just checks our character has all the crap it needs.
+/datum/dna/proc/check_integrity(var/mob/living/carbon/human/character)
+ if(character)
+ if(UI.len != DNA_UI_LENGTH)
+ ResetUIFrom(character)
+
+ if(length(struc_enzymes)!= 3*STRUCDNASIZE)
+ ResetSE()
+
+ if(length(unique_enzymes) != 32)
+ unique_enzymes = md5(character.real_name)
+ else
+ if(length(uni_identity) != 3*DNA_UI_LENGTH)
+ uni_identity = "00600200A00E0110148FC01300B0095BD7FD3F4"
+ if(length(struc_enzymes)!= 3*STRUCDNASIZE)
+ struc_enzymes = "43359156756131E13763334D1C369012032164D4FE4CD61544B6C03F251B6C60A42821D26BA3B0FD6"
+
+// BACK-COMPAT!
+// Initial DNA setup. I'm kind of wondering why the hell this doesn't just call the above.
+/datum/dna/proc/ready_dna(mob/living/carbon/human/character)
+ ResetUIFrom(character)
+
+ ResetSE()
+
+ unique_enzymes = md5(character.real_name)
+ reg_dna[unique_enzymes] = character.real_name
+
diff --git a/code/game/dna/dna2_domutcheck.dm b/code/game/dna/dna2_domutcheck.dm
new file mode 100644
index 00000000000..a53fc49c292
--- /dev/null
+++ b/code/game/dna/dna2_domutcheck.dm
@@ -0,0 +1,358 @@
+// (Re-)Apply mutations.
+// TODO: Turn into a /mob proc, change inj to a bitflag for various forms of differing behavior.
+// M: Mob to mess with
+// connected: Machine we're in, type unchecked so I doubt it's used beyond monkeying
+// flags: See below, bitfield.
+#define MUTCHK_FORCED 1
+/proc/domutcheck(var/mob/living/M, var/connected=null, var/flags=0)
+ for(var/datum/dna/gene/gene in dna_genes)
+ if(!M)
+ return
+ if(!gene.block)
+ continue
+
+ // Sanity checks, don't skip.
+ if(!gene.can_activate(M,flags))
+ //testing("[M] - Failed to activate [gene.name] (can_activate fail).")
+ continue
+
+ // Current state
+ var/gene_active = (gene.flags & GENE_ALWAYS_ACTIVATE)
+ if(!gene_active)
+ gene_active = M.dna.GetSEState(gene.block)
+
+ // Prior state
+ var/gene_prior_status = (gene.type in M.active_genes)
+
+ if((gene_active && !gene_prior_status) || (gene.flags & GENE_ALWAYS_ACTIVATE))
+ //testing("[gene.name] activated!")
+ gene.activate(M,connected,flags)
+ if(M)
+ if(!(gene.flags & GENE_ALWAYS_ACTIVATE))
+ M.active_genes |= gene.type
+ M.update_icon=1
+ else if(!gene_active && gene_prior_status)
+ //testing("[gene.name] deactivated!")
+ gene.deactivate(M,connected,flags)
+ if(M)
+ M.active_genes -= gene.type
+ M.update_icon = 1
+ //else
+ // testing("[M] - Failed to activate [gene.name] - [gene_active?"+":"-"]active, [gene_prior_status?"+":"-"]prior")
+
+
+ // PROC CONTINUES BELOW AFTER COMMENTED CODE.
+
+/* Old, inflexibile
+/proc/domutcheck(var/mob/living/M, var/connected, var/flags)
+ if (!M) return
+
+ M.dna.check_integrity()
+
+ M.disabilities = 0
+ M.sdisabilities = 0
+ var/old_mutations = M.mutations
+ M.mutations = list()
+ M.pass_flags = 0
+// M.see_in_dark = 2
+// M.see_invisible = 0
+
+ if(PLANT in old_mutations)
+ M.mutations.Add(PLANT)
+ if(SKELETON in old_mutations)
+ M.mutations.Add(SKELETON)
+ if(FAT in old_mutations)
+ M.mutations.Add(FAT)
+ if(HUSK in old_mutations)
+ M.mutations.Add(HUSK)
+
+ var/inj = (flags & MUTCHK_FROM_INJECTOR) == MUTCHK_FROM_INJECTOR
+ var/forced = (flags & MUTCHK_FORCED) == MUTCHK_FORCED
+
+ if(M.dna.GetSEState(NOBREATHBLOCK))
+ if(forced || probinj(45,inj) || (mNobreath in old_mutations))
+ M << "\blue You feel no need to breathe."
+ M.mutations.Add(mNobreath)
+ if(M.dna.GetSEState(REMOTEVIEWBLOCK))
+ if(forced || probinj(45,inj) || (mRemote in old_mutations))
+ M << "\blue Your mind expands"
+ M.mutations.Add(mRemote)
+ M.verbs += /mob/living/carbon/human/proc/remoteobserve
+ if(M.dna.GetSEState(REGENERATEBLOCK))
+ if(forced || probinj(45,inj) || (mRegen in old_mutations))
+ M << "\blue You feel better"
+ M.mutations.Add(mRegen)
+ if(M.dna.GetSEState(INCREASERUNBLOCK))
+ if(forced || probinj(45,inj) || (mRun in old_mutations))
+ M << "\blue Your leg muscles pulsate."
+ M.mutations.Add(mRun)
+ if(M.dna.GetSEState(REMOTETALKBLOCK))
+ if(forced || probinj(45,inj) || (mRemotetalk in old_mutations))
+ M << "\blue You expand your mind outwards"
+ M.mutations.Add(mRemotetalk)
+ M.verbs += /mob/living/carbon/human/proc/remotesay
+ if(M.dna.GetSEState(MORPHBLOCK))
+ if(forced || probinj(45,inj) || (mMorph in old_mutations))
+ M.mutations.Add(mMorph)
+ M << "\blue Your skin feels strange"
+ M.verbs += /mob/living/carbon/human/proc/morph
+ if(M.dna.GetSEState(COLDBLOCK))
+ if(!(COLD_RESISTANCE in old_mutations))
+ if(forced || probinj(15,inj) || (mHeatres in old_mutations))
+ M.mutations.Add(mHeatres)
+ M << "\blue Your skin is icy to the touch"
+ else
+ if(forced || probinj(5,inj) || (mHeatres in old_mutations))
+ M.mutations.Add(mHeatres)
+ M << "\blue Your skin is icy to the touch"
+ if(M.dna.GetSEState(HALLUCINATIONBLOCK))
+ if(forced || probinj(45,inj) || (mHallucination in old_mutations))
+ M.mutations.Add(mHallucination)
+ M << "\red Your mind says 'Hello'"
+ if(M.dna.GetSEState(NOPRINTSBLOCK))
+ if(forced || probinj(45,inj) || (mFingerprints in old_mutations))
+ M.mutations.Add(mFingerprints)
+ M << "\blue Your fingers feel numb"
+ if(M.dna.GetSEState(SHOCKIMMUNITYBLOCK))
+ if(forced || probinj(45,inj) || (mShock in old_mutations))
+ M.mutations.Add(mShock)
+ M << "\blue Your skin feels strange"
+ if(M.dna.GetSEState(SMALLSIZEBLOCK))
+ if(forced || probinj(45,inj) || (mSmallsize in old_mutations))
+ M << "\blue Your skin feels rubbery"
+ M.mutations.Add(mSmallsize)
+ M.pass_flags |= 1
+
+
+
+ if (M.dna.GetSEState(HULKBLOCK))
+ if(forced || probinj(5,inj) || (HULK in old_mutations))
+ M << "\blue Your muscles hurt."
+ M.mutations.Add(HULK)
+ if (M.dna.GetSEState(HEADACHEBLOCK))
+ M.disabilities |= EPILEPSY
+ M << "\red You get a headache."
+ if (M.dna.GetSEState(FAKEBLOCK))
+ M << "\red You feel strange."
+ if (prob(95))
+ if(prob(50))
+ randmutb(M)
+ else
+ randmuti(M)
+ else
+ randmutg(M)
+ if (M.dna.GetSEState(COUGHBLOCK))
+ M.disabilities |= COUGHING
+ M << "\red You start coughing."
+ if (M.dna.GetSEState(CLUMSYBLOCK))
+ M << "\red You feel lightheaded."
+ M.mutations.Add(CLUMSY)
+ if (M.dna.GetSEState(TWITCHBLOCK))
+ M.disabilities |= TOURETTES
+ M << "\red You twitch."
+ if (M.dna.GetSEState(XRAYBLOCK))
+ if(forced || probinj(30,inj) || (XRAY in old_mutations))
+ M << "\blue The walls suddenly disappear."
+// M.sight |= (SEE_MOBS|SEE_OBJS|SEE_TURFS)
+// M.see_in_dark = 8
+// M.see_invisible = 2
+ M.mutations.Add(XRAY)
+ if (M.dna.GetSEState(NERVOUSBLOCK))
+ M.disabilities |= NERVOUS
+ M << "\red You feel nervous."
+ if (M.dna.GetSEState(FIREBLOCK))
+ if(!(mHeatres in old_mutations))
+ if(forced || probinj(30,inj) || (COLD_RESISTANCE in old_mutations))
+ M << "\blue Your body feels warm."
+ M.mutations.Add(COLD_RESISTANCE)
+ else
+ if(forced || probinj(5,inj) || (COLD_RESISTANCE in old_mutations))
+ M << "\blue Your body feels warm."
+ M.mutations.Add(COLD_RESISTANCE)
+ if (M.dna.GetSEState(BLINDBLOCK))
+ M.sdisabilities |= BLIND
+ M << "\red You can't seem to see anything."
+ if (M.dna.GetSEState(TELEBLOCK))
+ if(forced || probinj(15,inj) || (TK in old_mutations))
+ M << "\blue You feel smarter."
+ M.mutations.Add(TK)
+ if (M.dna.GetSEState(DEAFBLOCK))
+ M.sdisabilities |= DEAF
+ M.ear_deaf = 1
+ M << "\red Its kinda quiet.."
+ if (M.dna.GetSEState(GLASSESBLOCK))
+ M.disabilities |= NEARSIGHTED
+ M << "Your eyes feel weird..."
+
+ /* If you want the new mutations to work, UNCOMMENT THIS.
+ if(istype(M, /mob/living/carbon))
+ for (var/datum/mutations/mut in global_mutations)
+ mut.check_mutation(M)
+ */
+
+//////////////////////////////////////////////////////////// Monkey Block
+ if (M.dna.GetSEState(MONKEYBLOCK) && istype(M, /mob/living/carbon/human))
+ // human > monkey
+ var/mob/living/carbon/human/H = M
+ H.monkeyizing = 1
+ var/list/implants = list() //Try to preserve implants.
+ for(var/obj/item/weapon/implant/W in H)
+ implants += W
+ W.loc = null
+
+ if(!connected)
+ for(var/obj/item/W in (H.contents-implants))
+ if (W==H.w_uniform) // will be teared
+ continue
+ H.drop_from_inventory(W)
+ M.monkeyizing = 1
+ M.canmove = 0
+ M.icon = null
+ M.invisibility = 101
+ var/atom/movable/overlay/animation = new( M.loc )
+ animation.icon_state = "blank"
+ animation.icon = 'icons/mob/mob.dmi'
+ animation.master = src
+ flick("h2monkey", animation)
+ sleep(48)
+ del(animation)
+
+
+ var/mob/living/carbon/monkey/O = null
+ if(H.species.primitive)
+ O = new H.species.primitive(src)
+ else
+ H.gib() //Trying to change the species of a creature with no primitive var set is messy.
+ return
+
+ if(M)
+ if (M.dna)
+ O.dna = M.dna
+ M.dna = null
+
+ if (M.suiciding)
+ O.suiciding = M.suiciding
+ M.suiciding = null
+
+
+ for(var/datum/disease/D in M.viruses)
+ O.viruses += D
+ D.affected_mob = O
+ M.viruses -= D
+
+
+ for(var/obj/T in (M.contents-implants))
+ del(T)
+
+ O.loc = M.loc
+
+ if(M.mind)
+ M.mind.transfer_to(O) //transfer our mind to the cute little monkey
+
+ if (connected) //inside dna thing
+ var/obj/machinery/dna_scannernew/C = connected
+ O.loc = C
+ C.occupant = O
+ connected = null
+ O.real_name = text("monkey ([])",copytext(md5(M.real_name), 2, 6))
+ O.take_overall_damage(M.getBruteLoss() + 40, M.getFireLoss())
+ O.adjustToxLoss(M.getToxLoss() + 20)
+ O.adjustOxyLoss(M.getOxyLoss())
+ O.stat = M.stat
+ O.a_intent = "hurt"
+ for (var/obj/item/weapon/implant/I in implants)
+ I.loc = O
+ I.implanted = O
+// O.update_icon = 1 //queue a full icon update at next life() call
+ del(M)
+ return
+
+ if (!M.dna.GetSEState(MONKEYBLOCK) && !istype(M, /mob/living/carbon/human))
+ // monkey > human,
+ var/mob/living/carbon/monkey/Mo = M
+ Mo.monkeyizing = 1
+ var/list/implants = list() //Still preserving implants
+ for(var/obj/item/weapon/implant/W in Mo)
+ implants += W
+ W.loc = null
+ if(!connected)
+ for(var/obj/item/W in (Mo.contents-implants))
+ Mo.drop_from_inventory(W)
+ M.monkeyizing = 1
+ M.canmove = 0
+ M.icon = null
+ M.invisibility = 101
+ var/atom/movable/overlay/animation = new( M.loc )
+ animation.icon_state = "blank"
+ animation.icon = 'icons/mob/mob.dmi'
+ animation.master = src
+ flick("monkey2h", animation)
+ sleep(48)
+ del(animation)
+
+ var/mob/living/carbon/human/O = new( src )
+ if(Mo.greaterform)
+ O.set_species(Mo.greaterform)
+
+ if (M.dna.GetUIState(DNA_UI_GENDER))
+ O.gender = FEMALE
+ else
+ O.gender = MALE
+
+ if (M)
+ if (M.dna)
+ O.dna = M.dna
+ M.dna = null
+
+ if (M.suiciding)
+ O.suiciding = M.suiciding
+ M.suiciding = null
+
+ for(var/datum/disease/D in M.viruses)
+ O.viruses += D
+ D.affected_mob = O
+ M.viruses -= D
+
+ //for(var/obj/T in M)
+ // del(T)
+
+ O.loc = M.loc
+
+ if(M.mind)
+ M.mind.transfer_to(O) //transfer our mind to the human
+
+ if (connected) //inside dna thing
+ var/obj/machinery/dna_scannernew/C = connected
+ O.loc = C
+ C.occupant = O
+ connected = null
+
+ var/i
+ while (!i)
+ var/randomname
+ if (O.gender == MALE)
+ randomname = capitalize(pick(first_names_male) + " " + capitalize(pick(last_names)))
+ else
+ randomname = capitalize(pick(first_names_female) + " " + capitalize(pick(last_names)))
+ if (findname(randomname))
+ continue
+ else
+ O.real_name = randomname
+ i++
+ O.UpdateAppearance()
+ O.take_overall_damage(M.getBruteLoss(), M.getFireLoss())
+ O.adjustToxLoss(M.getToxLoss())
+ O.adjustOxyLoss(M.getOxyLoss())
+ O.stat = M.stat
+ for (var/obj/item/weapon/implant/I in implants)
+ I.loc = O
+ I.implanted = O
+// O.update_icon = 1 //queue a full icon update at next life() call
+ del(M)
+ return
+//////////////////////////////////////////////////////////// Monkey Block
+ if(M)
+ M.update_icon = 1 //queue a full icon update at next life() call
+ return null
+/////////////////////////// DNA MISC-PROCS
+*/
diff --git a/code/game/dna/dna2_helpers.dm b/code/game/dna/dna2_helpers.dm
new file mode 100644
index 00000000000..216832f3cf7
--- /dev/null
+++ b/code/game/dna/dna2_helpers.dm
@@ -0,0 +1,175 @@
+/////////////////////////////
+// Helpers for DNA2
+/////////////////////////////
+
+// Pads 0s to t until length == u
+/proc/add_zero2(t, u)
+ var/temp1
+ while (length(t) < u)
+ t = "0[t]"
+ temp1 = t
+ if (length(t) > u)
+ temp1 = copytext(t,2,u+1)
+ return temp1
+
+// DNA Gene activation boundaries, see dna2.dm.
+// Returns a list object with 4 numbers.
+/proc/GetDNABounds(var/block)
+ var/list/BOUNDS=dna_activity_bounds[block]
+ if(!istype(BOUNDS))
+ return DNA_DEFAULT_BOUNDS
+ return BOUNDS
+
+// Give Random Bad Mutation to M
+/proc/randmutb(var/mob/living/M)
+ if(!M) return
+ M.dna.check_integrity()
+ var/block = pick(GLASSESBLOCK,COUGHBLOCK,FAKEBLOCK,NERVOUSBLOCK,CLUMSYBLOCK,TWITCHBLOCK,HEADACHEBLOCK,BLINDBLOCK,DEAFBLOCK,HALLUCINATIONBLOCK)
+ M.dna.SetSEState(block, 1)
+
+// Give Random Good Mutation to M
+/proc/randmutg(var/mob/living/M)
+ if(!M) return
+ M.dna.check_integrity()
+ var/block = pick(HULKBLOCK,XRAYBLOCK,FIREBLOCK,TELEBLOCK,NOBREATHBLOCK,REMOTEVIEWBLOCK,REGENERATEBLOCK,INCREASERUNBLOCK,REMOTETALKBLOCK,MORPHBLOCK,BLENDBLOCK,NOPRINTSBLOCK,SHOCKIMMUNITYBLOCK,SMALLSIZEBLOCK)
+ M.dna.SetSEState(block, 1)
+
+// Random Appearance Mutation
+/proc/randmuti(var/mob/living/M)
+ if(!M) return
+ M.dna.check_integrity()
+ M.dna.SetUIValue(rand(1,UNIDNASIZE),rand(1,4095))
+
+// Scramble UI or SE.
+/proc/scramble(var/UI, var/mob/M, var/prob)
+ if(!M) return
+ M.dna.check_integrity()
+ if(UI)
+ for(var/i = 1, i <= DNA_UI_LENGTH-1, i++)
+ if(prob(prob))
+ M.dna.SetUIValue(i,rand(1,4095),1)
+ M.dna.UpdateUI()
+ M.UpdateAppearance()
+
+ else
+ for(var/i = 1, i <= STRUCDNASIZE-1, i++)
+ if(prob(prob))
+ M.dna.SetSEValue(i,rand(1,4095),1)
+ M.dna.UpdateSE()
+ domutcheck(M, null)
+ return
+
+// I haven't yet figured out what the fuck this is supposed to do.
+/proc/miniscramble(input,rs,rd)
+ var/output
+ output = null
+ if (input == "C" || input == "D" || input == "E" || input == "F")
+ output = pick(prob((rs*10));"4",prob((rs*10));"5",prob((rs*10));"6",prob((rs*10));"7",prob((rs*5)+(rd));"0",prob((rs*5)+(rd));"1",prob((rs*10)-(rd));"2",prob((rs*10)-(rd));"3")
+ if (input == "8" || input == "9" || input == "A" || input == "B")
+ output = pick(prob((rs*10));"4",prob((rs*10));"5",prob((rs*10));"A",prob((rs*10));"B",prob((rs*5)+(rd));"C",prob((rs*5)+(rd));"D",prob((rs*5)+(rd));"2",prob((rs*5)+(rd));"3")
+ if (input == "4" || input == "5" || input == "6" || input == "7")
+ output = pick(prob((rs*10));"4",prob((rs*10));"5",prob((rs*10));"A",prob((rs*10));"B",prob((rs*5)+(rd));"C",prob((rs*5)+(rd));"D",prob((rs*5)+(rd));"2",prob((rs*5)+(rd));"3")
+ if (input == "0" || input == "1" || input == "2" || input == "3")
+ output = pick(prob((rs*10));"8",prob((rs*10));"9",prob((rs*10));"A",prob((rs*10));"B",prob((rs*10)-(rd));"C",prob((rs*10)-(rd));"D",prob((rs*5)+(rd));"E",prob((rs*5)+(rd));"F")
+ if (!output) output = "5"
+ return output
+
+// HELLO I MAKE BELL CURVES AROUND YOUR DESIRED TARGET
+// So a shitty way of replacing gaussian noise.
+// input: YOUR TARGET
+// rs: RAD STRENGTH
+// rd: DURATION
+/proc/miniscrambletarget(input,rs,rd)
+ var/output = null
+ switch(input)
+ if("0")
+ output = pick(prob((rs*10)+(rd));"0",prob((rs*10)+(rd));"1",prob((rs*10));"2",prob((rs*10)-(rd));"3")
+ if("1")
+ output = pick(prob((rs*10)+(rd));"0",prob((rs*10)+(rd));"1",prob((rs*10)+(rd));"2",prob((rs*10));"3",prob((rs*10)-(rd));"4")
+ if("2")
+ output = pick(prob((rs*10));"0",prob((rs*10)+(rd));"1",prob((rs*10)+(rd));"2",prob((rs*10)+(rd));"3",prob((rs*10));"4",prob((rs*10)-(rd));"5")
+ if("3")
+ output = pick(prob((rs*10)-(rd));"0",prob((rs*10));"1",prob((rs*10)+(rd));"2",prob((rs*10)+(rd));"3",prob((rs*10)+(rd));"4",prob((rs*10));"5",prob((rs*10)-(rd));"6")
+ if("4")
+ output = pick(prob((rs*10)-(rd));"1",prob((rs*10));"2",prob((rs*10)+(rd));"3",prob((rs*10)+(rd));"4",prob((rs*10)+(rd));"5",prob((rs*10));"6",prob((rs*10)-(rd));"7")
+ if("5")
+ output = pick(prob((rs*10)-(rd));"2",prob((rs*10));"3",prob((rs*10)+(rd));"4",prob((rs*10)+(rd));"5",prob((rs*10)+(rd));"6",prob((rs*10));"7",prob((rs*10)-(rd));"8")
+ if("6")
+ output = pick(prob((rs*10)-(rd));"3",prob((rs*10));"4",prob((rs*10)+(rd));"5",prob((rs*10)+(rd));"6",prob((rs*10)+(rd));"7",prob((rs*10));"8",prob((rs*10)-(rd));"9")
+ if("7")
+ output = pick(prob((rs*10)-(rd));"4",prob((rs*10));"5",prob((rs*10)+(rd));"6",prob((rs*10)+(rd));"7",prob((rs*10)+(rd));"8",prob((rs*10));"9",prob((rs*10)-(rd));"A")
+ if("8")
+ output = pick(prob((rs*10)-(rd));"5",prob((rs*10));"6",prob((rs*10)+(rd));"7",prob((rs*10)+(rd));"8",prob((rs*10)+(rd));"9",prob((rs*10));"A",prob((rs*10)-(rd));"B")
+ if("9")
+ output = pick(prob((rs*10)-(rd));"6",prob((rs*10));"7",prob((rs*10)+(rd));"8",prob((rs*10)+(rd));"9",prob((rs*10)+(rd));"A",prob((rs*10));"B",prob((rs*10)-(rd));"C")
+ if("10")//A
+ output = pick(prob((rs*10)-(rd));"7",prob((rs*10));"8",prob((rs*10)+(rd));"9",prob((rs*10)+(rd));"A",prob((rs*10)+(rd));"B",prob((rs*10));"C",prob((rs*10)-(rd));"D")
+ if("11")//B
+ output = pick(prob((rs*10)-(rd));"8",prob((rs*10));"9",prob((rs*10)+(rd));"A",prob((rs*10)+(rd));"B",prob((rs*10)+(rd));"C",prob((rs*10));"D",prob((rs*10)-(rd));"E")
+ if("12")//C
+ output = pick(prob((rs*10)-(rd));"9",prob((rs*10));"A",prob((rs*10)+(rd));"B",prob((rs*10)+(rd));"C",prob((rs*10)+(rd));"D",prob((rs*10));"E",prob((rs*10)-(rd));"F")
+ if("13")//D
+ output = pick(prob((rs*10)-(rd));"A",prob((rs*10));"B",prob((rs*10)+(rd));"C",prob((rs*10)+(rd));"D",prob((rs*10)+(rd));"E",prob((rs*10));"F")
+ if("14")//E
+ output = pick(prob((rs*10)-(rd));"B",prob((rs*10));"C",prob((rs*10)+(rd));"D",prob((rs*10)+(rd));"E",prob((rs*10)+(rd));"F")
+ if("15")//F
+ output = pick(prob((rs*10)-(rd));"C",prob((rs*10));"D",prob((rs*10)+(rd));"E",prob((rs*10)+(rd));"F")
+
+ if(!input || !output) //How did this happen?
+ output = "8"
+
+ return output
+
+// /proc/updateappearance has changed behavior, so it's been removed
+// Use mob.UpdateAppearance() instead.
+
+// Simpler. Don't specify UI in order for the mob to use its own.
+/mob/proc/UpdateAppearance(var/list/UI=null)
+ if(istype(src, /mob/living/carbon/human))
+ if(UI!=null)
+ src.dna.UI=UI
+ src.dna.UpdateUI()
+ dna.check_integrity()
+ var/mob/living/carbon/human/H = src
+ H.r_hair = dna.GetUIValueRange(DNA_UI_HAIR_R, 255)
+ H.g_hair = dna.GetUIValueRange(DNA_UI_HAIR_G, 255)
+ H.b_hair = dna.GetUIValueRange(DNA_UI_HAIR_B, 255)
+
+ H.r_facial = dna.GetUIValueRange(DNA_UI_BEARD_R, 255)
+ H.g_facial = dna.GetUIValueRange(DNA_UI_BEARD_G, 255)
+ H.b_facial = dna.GetUIValueRange(DNA_UI_BEARD_B, 255)
+
+ H.r_eyes = dna.GetUIValueRange(DNA_UI_EYES_R, 255)
+ H.g_eyes = dna.GetUIValueRange(DNA_UI_EYES_G, 255)
+ H.b_eyes = dna.GetUIValueRange(DNA_UI_EYES_B, 255)
+
+ var/new_s_tone = dna.GetUIValueRange(DNA_UI_SKIN_TONE, 220)
+ H.s_tone = 35 - max(min( round(new_s_tone), 220),1) //Warning MATH. Blame the person that wrote modules/client/preferences.dm, line 994
+
+ if (dna.GetUIState(DNA_UI_GENDER))
+ H.gender = FEMALE
+ else
+ H.gender = MALE
+
+ //Hair
+ var/hair = dna.GetUIValueRange(DNA_UI_HAIR_STYLE,hair_styles_list.len)
+ if((0 < hair) && (hair <= hair_styles_list.len))
+ H.h_style = hair_styles_list[hair]
+
+ //Facial Hair
+ var/beard = dna.GetUIValueRange(DNA_UI_BEARD_STYLE,facial_hair_styles_list.len)
+ if((0 < beard) && (beard <= facial_hair_styles_list.len))
+ H.f_style = facial_hair_styles_list[beard]
+
+ H.update_body(0)
+ H.update_hair()
+
+ return 1
+ else
+ return 0
+
+// Used below, simple injection modifier.
+/proc/probinj(var/pr, var/inj)
+ return prob(pr+inj*pr)
+
+/////////////////////////// DNA MISC-PROCS
diff --git a/code/game/dna/dna_modifier.dm b/code/game/dna/dna_modifier.dm
index 28598b175bb..6b91a6c4912 100644
--- a/code/game/dna/dna_modifier.dm
+++ b/code/game/dna/dna_modifier.dm
@@ -1,5 +1,37 @@
#define DNA_BLOCK_SIZE 3
+// Buffer datatype flags.
+#define DNA2_BUF_UI 1
+#define DNA2_BUF_UE 2
+#define DNA2_BUF_SE 4
+
+//list("data" = null, "owner" = null, "label" = null, "type" = null, "ue" = 0),
+/datum/dna2/record
+ var/datum/dna/dna = null
+ var/types=0
+ var/name="Empty"
+
+ // Stuff for cloners
+ var/id=null
+ var/implant=null
+ var/ckey=null
+ var/mind=null
+
+/datum/dna2/record/proc/GetData()
+ var/list/ser=list("data" = null, "owner" = null, "label" = null, "type" = null, "ue" = 0)
+ ser["ue"] = (types & DNA2_BUF_UE) == DNA2_BUF_UE
+ if(types & DNA2_BUF_SE)
+ ser["data"] = dna.SE
+ else
+ ser["data"] = dna.UI
+ ser["owner"] = src.dna.real_name
+ ser["label"] = name
+ if(types & DNA2_BUF_UI)
+ ser["type"] = "ui"
+ else
+ ser["type"] = "se"
+ return ser
+
/////////////////////////// DNA MACHINES
/obj/machinery/dna_scannernew
name = "\improper DNA modifier"
@@ -14,6 +46,7 @@
var/locked = 0
var/mob/living/carbon/occupant = null
var/obj/item/weapon/reagent_containers/glass/beaker = null
+ var/opened = 0
/obj/machinery/dna_scannernew/New()
..()
@@ -80,12 +113,6 @@
usr.loc = src
src.occupant = usr
src.icon_state = "scanner_1"
- /*
- for(var/obj/O in src) // THIS IS P. STUPID -- LOVE, DOOHL
- //O = null
- del(O)
- //Foreach goto(124)
- */
src.add_fingerprint(usr)
return
@@ -111,7 +138,12 @@
if (G.affecting.abiotic())
user << "\blue Subject cannot have abiotic items on."
return
- var/mob/M = G.affecting
+ put_in(G.affecting)
+ src.add_fingerprint(user)
+ del(G)
+ return
+
+/obj/machinery/dna_scannernew/proc/put_in(var/mob/M)
if(M.client)
M.client.perspective = EYE_PERSPECTIVE
M.client.eye = src
@@ -119,8 +151,6 @@
src.occupant = M
src.icon_state = "scanner_1"
- src.add_fingerprint(user)
-
// search for ghosts, if the corpse is empty and the scanner is connected to a cloner
if(locate(/obj/machinery/computer/cloning, get_step(src, NORTH)) \
|| locate(/obj/machinery/computer/cloning, get_step(src, SOUTH)) \
@@ -132,19 +162,11 @@
if(ghost.mind == M.mind)
ghost << "Your corpse has been placed into a cloning scanner. Return to your body if you want to be resurrected/cloned! (Verbs -> Ghost -> Re-enter corpse)"
break
- del(G)
return
/obj/machinery/dna_scannernew/proc/go_out()
if ((!( src.occupant ) || src.locked))
return
-/*
-// it's like this was -just- here to break constructed dna scanners -Pete
-// if that's not the case, slap my shit and uncomment this.
-// for(var/obj/O in src)
-// O.loc = src.loc
-*/
- //Foreach goto(30)
if (src.occupant.client)
src.occupant.client.eye = src.occupant.client.mob
src.occupant.client.perspective = MOB_PERSPECTIVE
@@ -205,11 +227,7 @@
var/selected_ui_target_hex = 1
var/radiation_duration = 2.0
var/radiation_intensity = 1.0
- var/list/buffers = list(
- list("data" = null, "owner" = null, "label" = null, "type" = null, "ue" = 0),
- list("data" = null, "owner" = null, "label" = null, "type" = null, "ue" = 0),
- list("data" = null, "owner" = null, "label" = null, "type" = null, "ue" = 0)
- )
+ var/list/datum/dna2/record/buffers[3]
var/irradiating = 0
var/injector_ready = 0 //Quick fix for issue 286 (screwdriver the screen twice to restore injector) -Pete
var/obj/machinery/dna_scannernew/connected = null
@@ -219,6 +237,7 @@
use_power = 1
idle_power_usage = 10
active_power_usage = 400
+ var/waiting_for_user_input=0 // Fix for #274 (Mash create block injector without answering dialog to make unlimited injectors) - N3X
/obj/machinery/computer/scan_consolenew/attackby(obj/item/I as obj, mob/user as mob)
if(istype(I, /obj/item/weapon/screwdriver))
@@ -302,19 +321,19 @@
return
return
-/obj/machinery/computer/scan_consolenew/proc/all_dna_blocks(var/buffer)
+/obj/machinery/computer/scan_consolenew/proc/all_dna_blocks(var/list/buffer)
var/list/arr = list()
- for(var/i = 1, i <= length(buffer)/3, i++)
- arr += "[i]:[copytext(buffer,i*3-2,i*3+1)]"
+ for(var/i = 1, i <= buffer.len, i++)
+ arr += "[i]:[EncodeDNABlock(buffer[i])]"
return arr
-/obj/machinery/computer/scan_consolenew/proc/setInjectorBlock(var/obj/item/weapon/dnainjector/I, var/blk, var/buffer)
+/obj/machinery/computer/scan_consolenew/proc/setInjectorBlock(var/obj/item/weapon/dnainjector/I, var/blk, var/datum/dna2/record/buffer)
var/pos = findtext(blk,":")
if(!pos) return 0
var/id = text2num(copytext(blk,1,pos))
if(!id) return 0
I.block = id
- I.dna = copytext(buffer,id*3-2,id*3+1)
+ I.buf = buffer
return 1
/obj/machinery/computer/scan_consolenew/attackby(obj/item/W as obj, mob/user as mob)
@@ -336,6 +355,7 @@
ui_interact(user)
/obj/machinery/computer/scan_consolenew/attack_ai(user as mob)
+ src.add_hiddenprint(user)
ui_interact(user)
/obj/machinery/computer/scan_consolenew/attack_hand(user as mob)
@@ -345,7 +365,7 @@
/**
* The ui_interact proc is used to open and update Nano UIs
* If ui_interact is not used then the UI will not update correctly
- * ui_interact is currently defined for /atom/movable
+ * ui_interact is currently defined for /atom/movable (which is inherited by /obj and /mob)
*
* @param user /mob The mob who is interacting with this ui
* @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
@@ -363,27 +383,26 @@
data["selectedMenuKey"] = selected_menu_key
data["locked"] = src.connected.locked
data["hasOccupant"] = connected.occupant ? 1 : 0
-
+
data["isInjectorReady"] = injector_ready
data["hasDisk"] = disk ? 1 : 0
var/diskData[0]
- if (!disk)
+ if (!disk || !disk.buf)
diskData["data"] = null
diskData["owner"] = null
diskData["label"] = null
diskData["type"] = null
diskData["ue"] = null
else
- diskData["data"] = disk.data
- diskData["owner"] = disk.owner
- diskData["label"] = disk.name
- diskData["type"] = disk.data_type
- diskData["ue"] = disk.ue
+ diskData = disk.buf.GetData()
data["disk"] = diskData
- data["buffers"] = buffers
+ var/list/new_buffers = list()
+ for(var/datum/dna2/record/buf in buffers)
+ new_buffers.Add(buf.GetData())
+ data["buffers"]=new_buffers
data["radiationIntensity"] = radiation_intensity
data["radiationDuration"] = radiation_duration
@@ -432,23 +451,19 @@
if (connected.beaker.reagents && connected.beaker.reagents.reagent_list.len)
for(var/datum/reagent/R in connected.beaker.reagents.reagent_list)
data["beakerVolume"] += R.volume
-
- if (!ui) // no ui has been passed, so we'll search for one
- {
- ui = nanomanager.get_open_ui(user, src, ui_key)
- }
+
+ // update the ui if it exists, returns null if no ui is passed/found
+ ui = nanomanager.try_update_ui(user, src, ui_key, ui, data)
if (!ui)
- // the ui does not exist, so we'll create a new one
+ // the ui does not exist, so we'll create a new() one
+ // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "dna_modifier.tmpl", "DNA Modifier Console", 660, 700)
- // When the UI is first opened this is the data it will use
- ui.set_initial_data(data)
+ // when the ui is first opened this is the data it will use
+ ui.set_initial_data(data)
+ // open the new ui window
ui.open()
- // Auto update every Master Controller tick
+ // auto update every Master Controller tick
ui.set_auto_update(1)
- else
- // The UI is already open so push the new data to it
- ui.push_data(data)
- return
/obj/machinery/computer/scan_consolenew/Topic(href, href_list)
if(..())
@@ -571,10 +586,7 @@
return 1 // return 1 forces an update to all Nano uis attached to src
if (href_list["pulseUIRadiation"])
- var/block
- var/newblock
- var/tstructure2
- block = getblock(getblock(src.connected.occupant.dna.uni_identity,src.selected_ui_block,DNA_BLOCK_SIZE),src.selected_ui_subblock,1)
+ var/block = src.connected.occupant.dna.GetUISubBlock(src.selected_ui_block,src.selected_ui_subblock)
irradiating = src.radiation_duration
var/lock_state = src.connected.locked
@@ -590,13 +602,8 @@
if (prob((80 + (src.radiation_duration / 2))))
block = miniscrambletarget(num2text(selected_ui_target), src.radiation_intensity, src.radiation_duration)
- newblock = null
- if (src.selected_ui_subblock == 1) newblock = block + getblock(getblock(src.connected.occupant.dna.uni_identity,src.selected_ui_block,DNA_BLOCK_SIZE),2,1) + getblock(getblock(src.connected.occupant.dna.uni_identity,src.selected_ui_block,DNA_BLOCK_SIZE),3,1)
- if (src.selected_ui_subblock == 2) newblock = getblock(getblock(src.connected.occupant.dna.uni_identity,src.selected_ui_block,DNA_BLOCK_SIZE),1,1) + block + getblock(getblock(src.connected.occupant.dna.uni_identity,src.selected_ui_block,DNA_BLOCK_SIZE),3,1)
- if (src.selected_ui_subblock == 3) newblock = getblock(getblock(src.connected.occupant.dna.uni_identity,src.selected_ui_block,DNA_BLOCK_SIZE),1,1) + getblock(getblock(src.connected.occupant.dna.uni_identity,src.selected_ui_block,DNA_BLOCK_SIZE),2,1) + block
- tstructure2 = setblock(src.connected.occupant.dna.uni_identity, src.selected_ui_block, newblock,DNA_BLOCK_SIZE)
- src.connected.occupant.dna.uni_identity = tstructure2
- updateappearance(src.connected.occupant,src.connected.occupant.dna.uni_identity)
+ src.connected.occupant.dna.SetUISubBlock(src.selected_ui_block,src.selected_ui_subblock,block)
+ src.connected.occupant.UpdateAppearance()
src.connected.occupant.radiation += (src.radiation_intensity+src.radiation_duration)
else
if (prob(20+src.radiation_intensity))
@@ -604,7 +611,7 @@
domutcheck(src.connected.occupant,src.connected)
else
randmuti(src.connected.occupant)
- updateappearance(src.connected.occupant,src.connected.occupant.dna.uni_identity)
+ src.connected.occupant.UpdateAppearance()
src.connected.occupant.radiation += ((src.radiation_intensity*2)+src.radiation_duration)
src.connected.locked = lock_state
return 1 // return 1 forces an update to all Nano uis attached to src
@@ -632,15 +639,13 @@
src.selected_se_block = select_block
if ((select_subblock <= DNA_BLOCK_SIZE) && (select_subblock >= 1))
src.selected_se_subblock = select_subblock
+ //testing("User selected block [selected_se_block] (sent [select_block]), subblock [selected_se_subblock] (sent [select_block]).")
return 1 // return 1 forces an update to all Nano uis attached to src
if (href_list["pulseSERadiation"])
- var/block
- var/newblock
- var/tstructure2
- var/oldblock
-
- block = getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),src.selected_se_subblock,1)
+ var/block = src.connected.occupant.dna.GetSESubBlock(src.selected_se_block,src.selected_se_subblock)
+ //var/original_block=block
+ //testing("Irradiating SE block [src.selected_se_block]:[src.selected_se_subblock] ([block])...")
irradiating = src.radiation_duration
var/lock_state = src.connected.locked
@@ -653,47 +658,37 @@
if(src.connected.occupant)
if (prob((80 + (src.radiation_duration / 2))))
- if ((src.selected_se_block != 2 || src.selected_se_block != 12 || src.selected_se_block != 8 || src.selected_se_block || 10) && prob (20))
- oldblock = src.selected_se_block
- block = miniscramble(block, src.radiation_intensity, src.radiation_duration)
- newblock = null
+ // FIXME: Find out what these corresponded to and change them to the WHATEVERBLOCK they need to be.
+ //if ((src.selected_se_block != 2 || src.selected_se_block != 12 || src.selected_se_block != 8 || src.selected_se_block || 10) && prob (20))
+ var/real_SE_block=selected_se_block
+ block = miniscramble(block, src.radiation_intensity, src.radiation_duration)
+ if(prob(20))
if (src.selected_se_block > 1 && src.selected_se_block < STRUCDNASIZE/2)
- src.selected_se_block++
+ real_SE_block++
else if (src.selected_se_block > STRUCDNASIZE/2 && src.selected_se_block < STRUCDNASIZE)
- src.selected_se_block--
- if (src.selected_se_subblock == 1) newblock = block + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),2,1) + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),3,1)
- if (src.selected_se_subblock == 2) newblock = getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),1,1) + block + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),3,1)
- if (src.selected_se_subblock == 3) newblock = getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),1,1) + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),2,1) + block
- tstructure2 = setblock(src.connected.occupant.dna.struc_enzymes, src.selected_se_block, newblock,DNA_BLOCK_SIZE)
- src.connected.occupant.dna.struc_enzymes = tstructure2
- domutcheck(src.connected.occupant,src.connected)
- src.connected.occupant.radiation += (src.radiation_intensity+src.radiation_duration)
- src.selected_se_block = oldblock
- else
- //
- block = miniscramble(block, src.radiation_intensity, src.radiation_duration)
- newblock = null
- if (src.selected_se_subblock == 1) newblock = block + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),2,1) + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),3,1)
- if (src.selected_se_subblock == 2) newblock = getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),1,1) + block + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),3,1)
- if (src.selected_se_subblock == 3) newblock = getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),1,1) + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),2,1) + block
- tstructure2 = setblock(src.connected.occupant.dna.struc_enzymes, src.selected_se_block, newblock,DNA_BLOCK_SIZE)
- src.connected.occupant.dna.struc_enzymes = tstructure2
- domutcheck(src.connected.occupant,src.connected)
- src.connected.occupant.radiation += (src.radiation_intensity+src.radiation_duration)
+ real_SE_block--
+
+ //testing("Irradiated SE block [real_SE_block]:[src.selected_se_subblock] ([original_block] now [block]) [(real_SE_block!=selected_se_block) ? "(SHIFTED)":""]!")
+ connected.occupant.dna.SetSESubBlock(real_SE_block,selected_se_subblock,block)
+ src.connected.occupant.radiation += (src.radiation_intensity+src.radiation_duration)
+ domutcheck(src.connected.occupant,src.connected)
else
+ src.connected.occupant.radiation += ((src.radiation_intensity*2)+src.radiation_duration)
if (prob(80-src.radiation_duration))
+ //testing("Random bad mut!")
randmutb(src.connected.occupant)
domutcheck(src.connected.occupant,src.connected)
else
randmuti(src.connected.occupant)
- updateappearance(src.connected.occupant,src.connected.occupant.dna.uni_identity)
- src.connected.occupant.radiation += ((src.radiation_intensity*2)+src.radiation_duration)
+ //testing("Random identity mut!")
+ src.connected.occupant.UpdateAppearance()
src.connected.locked = lock_state
return 1 // return 1 forces an update to all Nano uis attached to src
if(href_list["ejectBeaker"])
if(connected.beaker)
- connected.beaker.loc = connected.loc
+ var/obj/item/weapon/reagent_containers/glass/B = connected.beaker
+ B.loc = connected.loc
connected.beaker = null
return 1
@@ -704,18 +699,14 @@
// Transfer Buffer Management
if(href_list["bufferOption"])
var/bufferOption = href_list["bufferOption"]
-
+
// These bufferOptions do not require a bufferId
if (bufferOption == "wipeDisk")
if ((isnull(src.disk)) || (src.disk.read_only))
//src.temphtml = "Invalid disk. Please try again."
return 0
- src.disk.data = null
- src.disk.data_type = null
- src.disk.ue = null
- src.disk.owner = null
- src.disk.name = null
+ src.disk.buf=null
//src.temphtml = "Data saved."
return 1
@@ -724,12 +715,12 @@
return
src.disk.loc = get_turf(src)
src.disk = null
- return 1
-
+ return 1
+
// All bufferOptions from here on require a bufferId
if (!href_list["bufferId"])
return 0
-
+
var/bufferId = text2num(href_list["bufferId"])
if (bufferId < 1 || bufferId > 3)
@@ -737,56 +728,46 @@
if (bufferOption == "saveUI")
if(src.connected.occupant && src.connected.occupant.dna)
- src.buffers[bufferId]["ue"] = 0
- src.buffers[bufferId]["data"] = src.connected.occupant.dna.uni_identity
- if (!istype(src.connected.occupant,/mob/living/carbon/human))
- src.buffers[bufferId]["owner"] = src.connected.occupant.name
- else
- src.buffers[bufferId]["owner"] = src.connected.occupant.real_name
- src.buffers[bufferId]["label"] = "Unique Identifier"
- src.buffers[bufferId]["type"] = "ui"
+ var/datum/dna2/record/databuf=new
+ databuf.types = DNA2_BUF_UE
+ databuf.dna = src.connected.occupant.dna
+ databuf.name = "Unique Identifier"
+ src.buffers[bufferId] = databuf
return 1
if (bufferOption == "saveUIAndUE")
if(src.connected.occupant && src.connected.occupant.dna)
- src.buffers[bufferId]["data"] = src.connected.occupant.dna.uni_identity
- if (!istype(src.connected.occupant,/mob/living/carbon/human))
- src.buffers[bufferId]["owner"] = src.connected.occupant.name
- else
- src.buffers[bufferId]["owner"] = src.connected.occupant.real_name
- src.buffers[bufferId]["label"] = "Unique Identifier + Unique Enzymes"
- src.buffers[bufferId]["type"] = "ui"
- src.buffers[bufferId]["ue"] = 1
+ var/datum/dna2/record/databuf=new
+ databuf.types = DNA2_BUF_UI|DNA2_BUF_UE
+ databuf.dna = src.connected.occupant.dna
+ databuf.name = "Unique Identifier + Unique Enzymes"
+ src.buffers[bufferId] = databuf
return 1
if (bufferOption == "saveSE")
if(src.connected.occupant && src.connected.occupant.dna)
- src.buffers[bufferId]["ue"] = 0
- src.buffers[bufferId]["data"] = src.connected.occupant.dna.struc_enzymes
- if (!istype(src.connected.occupant,/mob/living/carbon/human))
- src.buffers[bufferId]["owner"] = src.connected.occupant.name
- else
- src.buffers[bufferId]["owner"] = src.connected.occupant.real_name
- src.buffers[bufferId]["label"] = "Structural Enzymes"
- src.buffers[bufferId]["type"] = "se"
+ var/datum/dna2/record/databuf=new
+ databuf.types = DNA2_BUF_SE
+ databuf.dna = src.connected.occupant.dna
+ databuf.name = "Structural Enzymes"
+ src.buffers[bufferId] = databuf
return 1
if (bufferOption == "clear")
- src.buffers[bufferId]["data"] = null
- src.buffers[bufferId]["owner"] = null
- src.buffers[bufferId]["label"] = null
- src.buffers[bufferId]["ue"] = null
+ src.buffers[bufferId]=null
return 1
if (bufferOption == "changeLabel")
- var/label = src.buffers[bufferId]["label"] ? src.buffers[bufferId]["label"] : "New Label"
- src.buffers[bufferId]["label"] = sanitize(input("New Label:", "Edit Label", label))
+ var/datum/dna2/record/buf = src.buffers[bufferId]
+ buf.name = buf.name ? src.buffers[bufferId]["label"] : "New Label"
+ buf.name = sanitize(input("New Label:", "Edit Label", buf.name))
+ src.buffers[bufferId] = buf
return 1
if (bufferOption == "transfer")
if (!src.connected.occupant || (NOCLONE in src.connected.occupant.mutations) || !src.connected.occupant.dna)
return
-
+
irradiating = 2
var/lock_state = src.connected.locked
src.connected.locked = 1//lock it
@@ -796,33 +777,37 @@
irradiating = 0
src.connected.locked = lock_state
-
- if (src.buffers[bufferId]["type"] == "ui")
- if (src.buffers[bufferId]["ue"])
- src.connected.occupant.real_name = src.buffers[bufferId]["owner"]
- src.connected.occupant.name = src.buffers[bufferId]["owner"]
- src.connected.occupant.dna.uni_identity = src.buffers[bufferId]["data"]
- updateappearance(src.connected.occupant,src.connected.occupant.dna.uni_identity)
- else if (src.buffers[bufferId]["type"] == "se")
- src.connected.occupant.dna.struc_enzymes = src.buffers[bufferId]["data"]
+
+ var/datum/dna2/record/buf = src.buffers[bufferId]
+
+ if ((buf.types & DNA2_BUF_UI))
+ if ((buf.types & DNA2_BUF_UE))
+ src.connected.occupant.real_name = buf.dna.real_name
+ src.connected.occupant.name = buf.dna.real_name
+ src.connected.occupant.UpdateAppearance(buf.dna.UI)
+ else if (buf.types & DNA2_BUF_SE)
+ src.connected.occupant.dna.SE = buf.dna.SE
+ src.connected.occupant.dna.UpdateSE()
domutcheck(src.connected.occupant,src.connected)
src.connected.occupant.radiation += rand(20,50)
return 1
if (bufferOption == "createInjector")
- if (src.injector_ready)
+ if (src.injector_ready || waiting_for_user_input)
+
var/success = 1
var/obj/item/weapon/dnainjector/I = new /obj/item/weapon/dnainjector
- I.dnatype = src.buffers[bufferId]["type"]
+ var/datum/dna2/record/buf = src.buffers[bufferId]
if(href_list["createBlockInjector"])
- var/blk = input(usr,"Select Block","Block") in all_dna_blocks(src.buffers[bufferId]["data"])
- success = setInjectorBlock(I,blk,src.buffers[bufferId]["data"])
+ waiting_for_user_input=1
+ var/blk = input(usr,"Select Block","Block") in all_dna_blocks(buf.GetData())
+ success = setInjectorBlock(I,blk,buf)
else
- I.dna = src.buffers[bufferId]["data"]
+ I.buf = buf
+ waiting_for_user_input=0
if(success)
I.loc = src.loc
- I.name += " ([src.buffers[bufferId]["label"]])"
- if (src.buffers[bufferId]["ue"]) I.ue = src.buffers[bufferId]["owner"] //lazy haw haw
+ I.name += " ([buf.name])"
//src.temphtml = "Injector created."
src.injector_ready = 0
spawn(300)
@@ -834,14 +819,11 @@
return 1
if (bufferOption == "loadDisk")
- if ((isnull(src.disk)) || (!src.disk.data) || (src.disk.data == ""))
+ if ((isnull(src.disk)) || (!src.disk.buf))
//src.temphtml = "Invalid disk. Please try again."
return 0
- src.buffers[bufferId]["data"] = src.disk.data
- src.buffers[bufferId]["type"] = src.disk.data_type
- src.buffers[bufferId]["ue"] = src.disk.ue
- src.buffers[bufferId]["owner"] = src.disk.owner
+ src.buffers[bufferId]=src.disk.buf
//src.temphtml = "Data loaded."
return 1
@@ -850,13 +832,12 @@
//src.temphtml = "Invalid disk. Please try again."
return 0
- src.disk.data = buffers[bufferId]["data"]
- src.disk.data_type = src.buffers[bufferId]["type"]
- src.disk.ue = src.buffers[bufferId]["ue"]
- src.disk.owner = src.buffers[bufferId]["owner"]
- src.disk.name = "data disk - '[src.buffers[bufferId]["owner"]]'"
+ var/datum/dna2/record/buf = src.buffers[bufferId]
+
+ src.disk.buf = buf
+ src.disk.name = "data disk - '[buf.dna.real_name]'"
//src.temphtml = "Data saved."
- return 1
+ return 1
/////////////////////////// DNA MACHINES
diff --git a/code/game/dna/genes/disabilities.dm b/code/game/dna/genes/disabilities.dm
new file mode 100644
index 00000000000..e312111f6f3
--- /dev/null
+++ b/code/game/dna/genes/disabilities.dm
@@ -0,0 +1,125 @@
+/////////////////////
+// DISABILITY GENES
+//
+// These activate either a mutation, disability, or sdisability.
+//
+// Gene is always activated.
+/////////////////////
+
+/datum/dna/gene/disability
+ name="DISABILITY"
+
+ // Mutation to give (or 0)
+ var/mutation=0
+
+ // Disability to give (or 0)
+ var/disability=0
+
+ // SDisability to give (or 0)
+ var/sdisability=0
+
+ // Activation message
+ var/activation_message=""
+
+ // Yay, you're no longer growing 3 arms
+ var/deactivation_message=""
+
+/datum/dna/gene/disability/can_activate(var/mob/M,var/flags)
+ return 1 // Always set!
+
+/datum/dna/gene/disability/activate(var/mob/M, var/connected, var/flags)
+ if(mutation && !(mutation in M.mutations))
+ M.mutations.Add(mutation)
+ if(disability)
+ M.disabilities|=disability
+ if(sdisability)
+ M.sdisabilities|=sdisability
+ if(activation_message)
+ M << "\red [activation_message]"
+
+/datum/dna/gene/disability/deactivate(var/mob/M, var/connected, var/flags)
+ if(mutation && (mutation in M.mutations))
+ M.mutations.Remove(mutation)
+ if(disability)
+ M.disabilities &= ~disability
+ if(sdisability)
+ M.sdisabilities &= ~sdisability
+ if(deactivation_message)
+ M << "\red [deactivation_message]"
+
+// Note: Doesn't seem to do squat, at the moment.
+/datum/dna/gene/disability/hallucinate
+ name="Hallucinate"
+ activation_message="Your mind says 'Hello'."
+ mutation=mHallucination
+
+ New()
+ block=HALLUCINATIONBLOCK
+
+/datum/dna/gene/disability/epilepsy
+ name="Epilepsy"
+ activation_message="You get a headache."
+ disability=EPILEPSY
+
+ New()
+ block=HEADACHEBLOCK
+
+/datum/dna/gene/disability/cough
+ name="Coughing"
+ activation_message="You start coughing."
+ disability=COUGHING
+
+ New()
+ block=COUGHBLOCK
+
+/datum/dna/gene/disability/clumsy
+ name="Clumsiness"
+ activation_message="You feel lightheaded."
+ mutation=CLUMSY
+
+ New()
+ block=CLUMSYBLOCK
+
+/datum/dna/gene/disability/tourettes
+ name="Tourettes"
+ activation_message="You twitch."
+ disability=TOURETTES
+
+ New()
+ block=TWITCHBLOCK
+
+/datum/dna/gene/disability/nervousness
+ name="Nervousness"
+ activation_message="You feel nervous."
+ disability=NERVOUS
+
+ New()
+ block=NERVOUSBLOCK
+
+/datum/dna/gene/disability/blindness
+ name="Blindness"
+ activation_message="You can't seem to see anything."
+ sdisability=BLIND
+
+ New()
+ block=BLINDBLOCK
+
+/datum/dna/gene/disability/deaf
+ name="Deafness"
+ activation_message="It's kinda quiet."
+ sdisability=DEAF
+
+ New()
+ block=DEAFBLOCK
+
+ activate(var/mob/M, var/connected, var/flags)
+ ..(M,connected,flags)
+ M.ear_deaf = 1
+
+/datum/dna/gene/disability/nearsighted
+ name="Nearsightedness"
+ activation_message="Your eyes feel weird..."
+ disability=NEARSIGHTED
+
+ New()
+ block=GLASSESBLOCK
\ No newline at end of file
diff --git a/code/game/dna/genes/gene.dm b/code/game/dna/genes/gene.dm
new file mode 100644
index 00000000000..3bf5b5e5f75
--- /dev/null
+++ b/code/game/dna/genes/gene.dm
@@ -0,0 +1,88 @@
+/**
+* Gene Datum
+*
+* domutcheck was getting pretty hairy. This is the solution.
+*
+* All genes are stored in a global variable to cut down on memory
+* usage.
+*
+* @author N3X15
+*/
+
+/datum/dna/gene
+ // Display name
+ var/name="BASE GENE"
+
+ // Probably won't get used but why the fuck not
+ var/desc="Oh god who knows what this does."
+
+ // Set in initialize()!
+ // What gene activates this?
+ var/block=0
+
+ // Any of a number of GENE_ flags.
+ var/flags=0
+
+// Return 1 if we can activate.
+// HANDLE MUTCHK_FORCED HERE!
+/datum/dna/gene/proc/can_activate(var/mob/M, var/flags)
+ return 0
+
+// Called when the gene activates. Do your magic here.
+/datum/dna/gene/proc/activate(var/mob/M, var/connected, var/flags)
+ return
+
+// Called when the gene deactivates. Undo your magic here.
+// Only called when the block is deactivated.
+/datum/dna/gene/proc/deactivate(var/mob/M, var/connected, var/flags)
+ return
+
+
+/////////////////////
+// BASIC GENES
+//
+// These just chuck in a mutation and display a message.
+//
+// Gene is activated:
+// 1. If mutation already exists in mob
+// 2. If the probability roll succeeds
+// 3. Activation is forced (done in domutcheck)
+/////////////////////
+
+
+/datum/dna/gene/basic
+ name="BASIC GENE"
+
+ // Mutation to give
+ var/mutation=0
+
+ // Activation probability
+ var/activation_prob=45
+
+ // Possible activation messages
+ var/list/activation_messages=list()
+
+ // Possible deactivation messages
+ var/list/deactivation_messages=list()
+
+/datum/dna/gene/basic/can_activate(var/mob/M,var/flags)
+ if(mutation==0)
+ return 0
+
+ // Probability check
+ if(flags & MUTCHK_FORCED || probinj(activation_prob,(flags&MUTCHK_FORCED)))
+ return 1
+
+ return 0
+
+/datum/dna/gene/basic/activate(var/mob/M)
+ M.mutations.Add(mutation)
+ if(activation_messages.len)
+ var/msg = pick(activation_messages)
+ M << "\blue [msg]"
+
+/datum/dna/gene/basic/deactivate(var/mob/M)
+ M.mutations.Remove(mutation)
+ if(deactivation_messages.len)
+ var/msg = pick(deactivation_messages)
+ M << "\red [msg]"
\ No newline at end of file
diff --git a/code/game/dna/genes/monkey.dm b/code/game/dna/genes/monkey.dm
new file mode 100644
index 00000000000..952f7df0f48
--- /dev/null
+++ b/code/game/dna/genes/monkey.dm
@@ -0,0 +1,170 @@
+/datum/dna/gene/monkey
+ name="Monkey"
+
+/datum/dna/gene/monkey/New()
+ block=MONKEYBLOCK
+
+/datum/dna/gene/monkey/can_activate(var/mob/M,var/flags)
+ return istype(M, /mob/living/carbon/human) || istype(M,/mob/living/carbon/monkey)
+
+/datum/dna/gene/monkey/activate(var/mob/living/M, var/connected, var/flags)
+ if(!istype(M,/mob/living/carbon/human))
+ return
+ var/mob/living/carbon/human/H = M
+ H.monkeyizing = 1
+ var/list/implants = list() //Try to preserve implants.
+ for(var/obj/item/weapon/implant/W in H)
+ implants += W
+ W.loc = null
+
+ if(!connected)
+ for(var/obj/item/W in (H.contents-implants))
+ if (W==H.w_uniform) // will be teared
+ continue
+ H.drop_from_inventory(W)
+ M.monkeyizing = 1
+ M.canmove = 0
+ M.icon = null
+ M.invisibility = 101
+ var/atom/movable/overlay/animation = new( M.loc )
+ animation.icon_state = "blank"
+ animation.icon = 'icons/mob/mob.dmi'
+ animation.master = src
+ flick("h2monkey", animation)
+ sleep(48)
+ del(animation)
+
+
+ var/mob/living/carbon/monkey/O = null
+ if(H.species.primitive)
+ O = new H.species.primitive(src)
+ else
+ H.gib() //Trying to change the species of a creature with no primitive var set is messy.
+ return
+
+ if(M)
+ if (M.dna)
+ O.dna = M.dna
+ M.dna = null
+
+ if (M.suiciding)
+ O.suiciding = M.suiciding
+ M.suiciding = null
+
+
+ for(var/datum/disease/D in M.viruses)
+ O.viruses += D
+ D.affected_mob = O
+ M.viruses -= D
+
+
+ for(var/obj/T in (M.contents-implants))
+ del(T)
+
+ O.loc = M.loc
+
+ if(M.mind)
+ M.mind.transfer_to(O) //transfer our mind to the cute little monkey
+
+ if (connected) //inside dna thing
+ var/obj/machinery/dna_scannernew/C = connected
+ O.loc = C
+ C.occupant = O
+ connected = null
+ O.real_name = text("monkey ([])",copytext(md5(M.real_name), 2, 6))
+ O.take_overall_damage(M.getBruteLoss() + 40, M.getFireLoss())
+ O.adjustToxLoss(M.getToxLoss() + 20)
+ O.adjustOxyLoss(M.getOxyLoss())
+ O.stat = M.stat
+ O.a_intent = "hurt"
+ for (var/obj/item/weapon/implant/I in implants)
+ I.loc = O
+ I.implanted = O
+// O.update_icon = 1 //queue a full icon update at next life() call
+ del(M)
+ return
+
+/datum/dna/gene/monkey/deactivate(var/mob/living/M, var/connected, var/flags)
+ if(!istype(M,/mob/living/carbon/monkey))
+ return
+ var/mob/living/carbon/monkey/Mo = M
+ Mo.monkeyizing = 1
+ var/list/implants = list() //Still preserving implants
+ for(var/obj/item/weapon/implant/W in Mo)
+ implants += W
+ W.loc = null
+ if(!connected)
+ for(var/obj/item/W in (Mo.contents-implants))
+ Mo.drop_from_inventory(W)
+ M.monkeyizing = 1
+ M.canmove = 0
+ M.icon = null
+ M.invisibility = 101
+ var/atom/movable/overlay/animation = new( M.loc )
+ animation.icon_state = "blank"
+ animation.icon = 'icons/mob/mob.dmi'
+ animation.master = src
+ flick("monkey2h", animation)
+ sleep(48)
+ del(animation)
+
+ var/mob/living/carbon/human/O = new( src )
+ if(Mo.greaterform)
+ O.set_species(Mo.greaterform)
+
+ if (M.dna.GetUIState(DNA_UI_GENDER))
+ O.gender = FEMALE
+ else
+ O.gender = MALE
+
+ if (M)
+ if (M.dna)
+ O.dna = M.dna
+ M.dna = null
+
+ if (M.suiciding)
+ O.suiciding = M.suiciding
+ M.suiciding = null
+
+ for(var/datum/disease/D in M.viruses)
+ O.viruses += D
+ D.affected_mob = O
+ M.viruses -= D
+
+ //for(var/obj/T in M)
+ // del(T)
+
+ O.loc = M.loc
+
+ if(M.mind)
+ M.mind.transfer_to(O) //transfer our mind to the human
+
+ if (connected) //inside dna thing
+ var/obj/machinery/dna_scannernew/C = connected
+ O.loc = C
+ C.occupant = O
+ connected = null
+
+ var/i
+ while (!i)
+ var/randomname
+ if (O.gender == MALE)
+ randomname = capitalize(pick(first_names_male) + " " + capitalize(pick(last_names)))
+ else
+ randomname = capitalize(pick(first_names_female) + " " + capitalize(pick(last_names)))
+ if (findname(randomname))
+ continue
+ else
+ O.real_name = randomname
+ i++
+ O.UpdateAppearance()
+ O.take_overall_damage(M.getBruteLoss(), M.getFireLoss())
+ O.adjustToxLoss(M.getToxLoss())
+ O.adjustOxyLoss(M.getOxyLoss())
+ O.stat = M.stat
+ for (var/obj/item/weapon/implant/I in implants)
+ I.loc = O
+ I.implanted = O
+// O.update_icon = 1 //queue a full icon update at next life() call
+ del(M)
+ return
\ No newline at end of file
diff --git a/code/game/dna/genes/powers.dm b/code/game/dna/genes/powers.dm
new file mode 100644
index 00000000000..a8a9eefee7d
--- /dev/null
+++ b/code/game/dna/genes/powers.dm
@@ -0,0 +1,167 @@
+///////////////////////////////////
+// POWERS
+///////////////////////////////////
+
+/datum/dna/gene/basic/nobreath
+ name="No Breathing"
+ activation_messages=list("You feel no need to breathe.")
+ mutation=mNobreath
+
+ New()
+ block=NOBREATHBLOCK
+
+/datum/dna/gene/basic/remoteview
+ name="Remote Viewing"
+ activation_messages=list("Your mind expands.")
+ mutation=mRemote
+
+ New()
+ block=REMOTEVIEWBLOCK
+
+ activate(var/mob/M, var/connected, var/flags)
+ ..(M,connected,flags)
+ M.verbs += /mob/living/carbon/human/proc/remoteobserve
+
+/datum/dna/gene/basic/regenerate
+ name="Regenerate"
+ activation_messages=list("You feel better.")
+ mutation=mRegen
+
+ New()
+ block=REGENERATEBLOCK
+
+/datum/dna/gene/basic/increaserun
+ name="Super Speed"
+ activation_messages=list("Your leg muscles pulsate.")
+ mutation=mRun
+
+ New()
+ block=INCREASERUNBLOCK
+
+/datum/dna/gene/basic/remotetalk
+ name="Telepathy"
+ activation_messages=list("You expand your mind outwards.")
+ mutation=mRemotetalk
+
+ New()
+ block=REMOTETALKBLOCK
+
+ activate(var/mob/M, var/connected, var/flags)
+ ..(M,connected,flags)
+ M.verbs += /mob/living/carbon/human/proc/remotesay
+
+/datum/dna/gene/basic/morph
+ name="Morph"
+ activation_messages=list("Your skin feels strange.")
+ mutation=mMorph
+
+ New()
+ block=MORPHBLOCK
+
+ activate(var/mob/M)
+ ..(M)
+ M.verbs += /mob/living/carbon/human/proc/morph
+
+/* Not used on bay
+/datum/dna/gene/basic/heat_resist
+ name="Heat Resistance"
+ activation_messages=list("Your skin is icy to the touch.")
+ mutation=mHeatres
+
+ New()
+ block=COLDBLOCK
+
+ can_activate(var/mob/M,var/flags)
+ // Probability check
+ var/_prob = 15
+ if(COLD_RESISTANCE in M.mutations)
+ _prob=5
+ if(probinj(_prob,(flags&MUTCHK_FORCED)))
+ return 1
+*/
+
+/datum/dna/gene/basic/cold_resist
+ name="Cold Resistance"
+ activation_messages=list("Your body is filled with warmth.")
+ mutation=COLD_RESISTANCE
+
+ New()
+ block=FIREBLOCK
+
+ can_activate(var/mob/M,var/flags)
+
+ // Probability check
+ var/_prob=30
+ //if(mHeatres in M.mutations)
+ // _prob=5
+ if(probinj(_prob,(flags&MUTCHK_FORCED)))
+ return 1
+
+/datum/dna/gene/basic/noprints
+ name="No Prints"
+ activation_messages=list("Your fingers feel numb.")
+ mutation=mFingerprints
+
+ New()
+ block=NOPRINTSBLOCK
+
+/datum/dna/gene/basic/noshock
+ name="Shock Immunity"
+ activation_messages=list("Your skin feels strange.")
+ mutation=mShock
+
+ New()
+ block=SHOCKIMMUNITYBLOCK
+
+/datum/dna/gene/basic/midget
+ name="Midget"
+ activation_messages=list("Your skin feels rubbery.")
+ mutation=mSmallsize
+
+ New()
+ block=SMALLSIZEBLOCK
+
+ can_activate(var/mob/M,var/flags)
+ // Can't be big and small.
+ if(HULK in M.mutations)
+ return 0
+ return ..(M,flags)
+
+ activate(var/mob/M, var/connected, var/flags)
+ ..(M,connected,flags)
+ M.pass_flags |= 1
+
+ deactivate(var/mob/M, var/connected, var/flags)
+ ..(M,connected,flags)
+ M.pass_flags &= ~1 //This may cause issues down the track, but offhand I can't think of any other way for humans to get passtable short of varediting so it should be fine. ~Z
+
+/datum/dna/gene/basic/hulk
+ name="Hulk"
+ activation_messages=list("Your muscles hurt.")
+ mutation=HULK
+
+ New()
+ block=HULKBLOCK
+
+ can_activate(var/mob/M,var/flags)
+ // Can't be big and small.
+ if(mSmallsize in M.mutations)
+ return 0
+ return ..(M,flags)
+
+/datum/dna/gene/basic/xray
+ name="X-Ray Vision"
+ activation_messages=list("The walls suddenly disappear.")
+ mutation=XRAY
+
+ New()
+ block=XRAYBLOCK
+
+/datum/dna/gene/basic/tk
+ name="Telekenesis"
+ activation_messages=list("You feel smarter.")
+ mutation=TK
+ activation_prob=15
+
+ New()
+ block=TELEBLOCK
\ No newline at end of file
diff --git a/code/game/gamemodes/blob/blobs/shield.dm b/code/game/gamemodes/blob/blobs/shield.dm
index 4c77520846a..0e1b6c07eb4 100644
--- a/code/game/gamemodes/blob/blobs/shield.dm
+++ b/code/game/gamemodes/blob/blobs/shield.dm
@@ -6,7 +6,7 @@
density = 1
opacity = 0
anchored = 1
- health = 100
+ health = 60
brute_resist = 1
fire_resist = 2
diff --git a/code/game/gamemodes/changeling/changeling_powers.dm b/code/game/gamemodes/changeling/changeling_powers.dm
index e66aed88b87..a552ac1cd74 100644
--- a/code/game/gamemodes/changeling/changeling_powers.dm
+++ b/code/game/gamemodes/changeling/changeling_powers.dm
@@ -187,7 +187,7 @@
src.dna = chosen_dna
src.real_name = chosen_dna.real_name
src.flavor_text = ""
- updateappearance(src, src.dna.uni_identity)
+ src.UpdateAppearance()
domutcheck(src, null)
src.verbs -= /mob/proc/changeling_transform
@@ -205,6 +205,10 @@
var/datum/changeling/changeling = changeling_power(1,0,0)
if(!changeling) return
+ if(src.has_brain_worms())
+ src << "We cannot perform this ability at the present time!"
+ return
+
var/mob/living/carbon/C = src
changeling.chem_charges--
C.remove_changeling_powers()
@@ -314,7 +318,7 @@
W.layer = initial(W.layer)
var/mob/living/carbon/human/O = new /mob/living/carbon/human( src )
- if (isblockon(getblock(C.dna.uni_identity, 11,3),11))
+ if (C.dna.GetUIState(DNA_UI_GENDER))
O.gender = FEMALE
else
O.gender = MALE
@@ -327,7 +331,7 @@
O.loc = C.loc
- updateappearance(O,O.dna.uni_identity)
+ O.UpdateAppearance()
domutcheck(O, null)
O.setToxLoss(C.getToxLoss())
O.adjustBruteLoss(C.getBruteLoss())
@@ -370,24 +374,24 @@
if(changeling_power(20,1,100,DEAD))
// charge the changeling chemical cost for stasis
changeling.chem_charges -= 20
-
+
// restore us to health
C.rejuvenate()
-
+
// remove our fake death flag
C.status_flags &= ~(FAKEDEATH)
-
+
// let us move again
C.update_canmove()
-
+
// re-add out changeling powers
- C.make_changeling()
-
+ C.make_changeling()
+
// sending display messages
C << "We have regenerated."
C.visible_message("[src] appears to wake from the dead, having healed all wounds.")
-
-
+
+
feedback_add_details("changeling_powers","FD")
return 1
@@ -719,7 +723,7 @@ var/list/datum/dna/hivemind_bank = list()
T.visible_message("[T] transforms!")
T.dna = chosen_dna
T.real_name = chosen_dna.real_name
- updateappearance(T, T.dna.uni_identity)
+ T.UpdateAppearance()
domutcheck(T, null)
feedback_add_details("changeling_powers","TS")
return 1
diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm
index 2d408a1a4ff..ac89f046472 100644
--- a/code/game/gamemodes/cult/ritual.dm
+++ b/code/game/gamemodes/cult/ritual.dm
@@ -248,7 +248,7 @@ var/engwords = list("travel", "blood", "join", "hell", "destroy", "technology",
Drain Blood
This rune instantly heals you of some brute damage at the expense of a person placed on top of the rune. Whenever you invoke a drain rune, ALL drain runes on the station are activated, draining blood from anyone located on top of those runes. This includes yourself, though the blood you drain from yourself just comes back to you. This might help you identify this rune when studying words. One drain gives up to 25HP per each victim, but you can repeat it if you need more. Draining only works on living people, so you might need to recharge your "Battery" once its empty. Drinking too much blood at once might cause blood hunger.
Raise Dead
- This rune allows for the resurrection of any dead person. You will need a dead human body and a living human sacrifice. Make 2 raise dead runes. Put a living non-braindead human on top of one, and a dead body on the other one. When you invoke the rune, the life force of the living human will be transferred into the dead body, allowing a ghost standing on top of the dead body to enter it, instantly and fully healing it. Use other runes to ensure there is a ghost ready to be resurrected.
+ This rune allows for the resurrection of any dead person. You will need a dead human body and a living human sacrifice. Make 2 raise dead runes. Put a living, awake human on top of one, and a dead body on the other one. When you invoke the rune, the life force of the living human will be transferred into the dead body, allowing a ghost standing on top of the dead body to enter it, instantly and fully healing it. Use other runes to ensure there is a ghost ready to be resurrected.
Hide runes
This rune makes all nearby runes completely invisible. They are still there and will work if activated somehow, but you cannot invoke them directly if you do not see them.
Reveal runes
diff --git a/code/game/gamemodes/events.dm b/code/game/gamemodes/events.dm
index b9f68fb143c..5b1b1494b59 100644
--- a/code/game/gamemodes/events.dm
+++ b/code/game/gamemodes/events.dm
@@ -163,8 +163,8 @@
continue
var/datum/disease/dnaspread/D = new
D.strain_data["name"] = H.real_name
- D.strain_data["UI"] = H.dna.uni_identity
- D.strain_data["SE"] = H.dna.struc_enzymes
+ D.strain_data["UI"] = H.dna.UI
+ D.strain_data["SE"] = H.dna.SE
D.carrier = 1
D.holder = H
D.affected_mob = H
diff --git a/code/game/gamemodes/events/holidays/Christmas.dm b/code/game/gamemodes/events/holidays/Christmas.dm
index 2ee79e7c65b..72d42318e60 100644
--- a/code/game/gamemodes/events/holidays/Christmas.dm
+++ b/code/game/gamemodes/events/holidays/Christmas.dm
@@ -4,8 +4,8 @@
for(var/turf/simulated/floor/T in orange(1,xmas))
for(var/i=1,i<=rand(1,5),i++)
new /obj/item/weapon/a_gift(T)
- for(var/mob/living/simple_animal/corgi/Ian/Ian in mob_list)
- Ian.place_on_head(new /obj/item/clothing/head/helmet/space/santahat(Ian))
+ //for(var/mob/living/simple_animal/corgi/Ian/Ian in mob_list)
+ // Ian.place_on_head(new /obj/item/clothing/head/helmet/space/santahat(Ian))
/proc/ChristmasEvent()
for(var/obj/structure/flora/tree/pine/xmas in world)
diff --git a/code/game/gamemodes/events/holidays/Holidays.dm b/code/game/gamemodes/events/holidays/Holidays.dm
index d2481eae441..2cd06199bd8 100644
--- a/code/game/gamemodes/events/holidays/Holidays.dm
+++ b/code/game/gamemodes/events/holidays/Holidays.dm
@@ -12,6 +12,10 @@ var/global/Holiday = null
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// ~Carn
+/hook/startup/proc/updateHoliday()
+ Get_Holiday()
+ return 1
+
//sets up the Holiday global variable. Shouldbe called on game configuration or something.
/proc/Get_Holiday()
if(!Holiday) return // Holiday stuff was not enabled in the config!
diff --git a/code/game/gamemodes/events/ninja_abilities.dm b/code/game/gamemodes/events/ninja_abilities.dm
index 9245c740e07..11109af279d 100644
--- a/code/game/gamemodes/events/ninja_abilities.dm
+++ b/code/game/gamemodes/events/ninja_abilities.dm
@@ -57,7 +57,7 @@ Not sure why this would be useful (it's not) but whatever. Ninjas need their smo
if(!ninjacost(,2))
var/mob/living/carbon/human/U = affecting
U << "\blue There are [s_bombs] smoke bombs remaining."
- var/datum/effect/effect/system/bad_smoke_spread/smoke = new /datum/effect/effect/system/bad_smoke_spread()
+ var/datum/effect/effect/system/smoke_spread/bad/smoke = new /datum/effect/effect/system/smoke_spread/bad()
smoke.set_up(10, 0, U.loc)
smoke.start()
playsound(U.loc, 'sound/effects/bamf.ogg', 50, 2)
@@ -69,12 +69,12 @@ Not sure why this would be useful (it's not) but whatever. Ninjas need their smo
//=======//RIGHT CLICK TELEPORT//=======//
//Right click to teleport somewhere, almost exactly like admin jump to turf.
/obj/item/clothing/suit/space/space_ninja/proc/ninjashift(turf/T in oview())
- set name = "Phase Shift (1E)"
+ set name = "Phase Shift (400E)"
set desc = "Utilizes the internal VOID-shift device to rapidly transit to a destination in view."
set category = null//So it does not show up on the panel but can still be right-clicked.
set src = usr.contents//Fixes verbs not attaching properly for objects. Praise the DM reference guide!
- var/C = 200
+ var/C = 40
if(!ninjacost(C,1))
var/mob/living/carbon/human/U = affecting
var/turf/mobloc = get_turf(U.loc)//To make sure that certain things work properly below.
@@ -83,6 +83,7 @@ Not sure why this would be useful (it's not) but whatever. Ninjas need their smo
playsound(U.loc, 'sound/effects/sparks4.ogg', 50, 1)
anim(mobloc,src,'icons/mob/mob.dmi',,"phaseout",,U.dir)
+ cell.use(C*10)
handle_teleport_grab(T, U)
U.loc = T
@@ -92,19 +93,19 @@ Not sure why this would be useful (it's not) but whatever. Ninjas need their smo
playsound(U.loc, 'sound/effects/sparks2.ogg', 50, 1)
anim(U.loc,U,'icons/mob/mob.dmi',,"phasein",,U.dir)
else
- U << "\red You cannot teleport into solid walls or from solid matter"
+ U << "\red You cannot teleport into solid walls or from solid matter."
return
//=======//EM PULSE//=======//
//Disables nearby tech equipment.
/obj/item/clothing/suit/space/space_ninja/proc/ninjapulse()
- set name = "EM Burst (1,000E)"
+ set name = "EM Burst (2,000E)"
set desc = "Disable any nearby technology with a electro-magnetic pulse."
set category = "Ninja Ability"
set popup_menu = 0
- var/C = 250
- if(!ninjacost(C,100)) // EMP's now cost 1,000Energy about 30%
+ var/C = 200
+ if(!ninjacost(C,0)) // EMP's now cost 1,000Energy about 30%
var/mob/living/carbon/human/U = affecting
playsound(U.loc, 'sound/effects/EMPulse.ogg', 60, 2)
empulse(U, 2, 3) //Procs sure are nice. Slightly weaker than wizard's disable tch.
@@ -115,13 +116,13 @@ Not sure why this would be useful (it's not) but whatever. Ninjas need their smo
//=======//ENERGY BLADE//=======//
//Summons a blade of energy in active hand.
/obj/item/clothing/suit/space/space_ninja/proc/ninjablade()
- set name = "Energy Blade (20E)"
+ set name = "Energy Blade (500E)"
set desc = "Create a focused beam of energy in your active hand."
set category = "Ninja Ability"
set popup_menu = 0
var/C = 50
- if(!ninjacost(C, 800)) //Same spawn cost but higher upkeep cost
+ if(!ninjacost(C,0)) //Same spawn cost but higher upkeep cost
var/mob/living/carbon/human/U = affecting
if(!kamikaze)
if(!U.get_active_hand()&&!istype(U.get_inactive_hand(), /obj/item/weapon/melee/energy/blade))
@@ -148,12 +149,12 @@ Not sure why this would be useful (it's not) but whatever. Ninjas need their smo
/*Shoots ninja stars at random people.
This could be a lot better but I'm too tired atm.*/
/obj/item/clothing/suit/space/space_ninja/proc/ninjastar()
- set name = "Energy Star (1,000E)"
+ set name = "Energy Star (800E)"
set desc = "Launches an energy star at a random living target."
set category = "Ninja Ability"
set popup_menu = 0
- var/C = 50
+ var/C = 80
if(!ninjacost(C,1))
var/mob/living/carbon/human/U = affecting
var/targets[] = list()//So yo can shoot while yo throw dawg
@@ -173,7 +174,7 @@ This could be a lot better but I'm too tired atm.*/
A.current = curloc
A.yo = targloc.y - curloc.y
A.xo = targloc.x - curloc.x
- cell.use(C*100)// Ninja stars now cost 100 energy, stil la fair chunk to avoid spamming, will run out of power quickly if used 3 or more times
+ cell.use(C*10)
A.process()
else
U << "\red There are no targets in view."
@@ -183,13 +184,13 @@ This could be a lot better but I'm too tired atm.*/
/*Allows the ninja to capture people, I guess.
Must right click on a mob to activate.*/
/obj/item/clothing/suit/space/space_ninja/proc/ninjanet(mob/living/carbon/M in oview())//Only living carbon mobs.
- set name = "Energy Net (8,000E)"
+ set name = "Energy Net (7,000E)"
set desc = "Captures a fallen opponent in a net of energy. Will teleport them to a holding facility after 30 seconds."
set category = null
set src = usr.contents
- var/C = 500
- if(!ninjacost(C,80)&&iscarbon(M)) // Nets now cost 8,000
+ var/C = 700
+ if(!ninjacost(C,0)&&iscarbon(M))
var/mob/living/carbon/human/U = affecting
if(M.client)//Monkeys without a client can still step_to() and bypass the net. Also, netting inactive people is lame.
//if(M)//DEBUG
@@ -200,7 +201,7 @@ Must right click on a mob to activate.*/
return
spawn(0)
U.Beam(M,"n_beam",,15)
- M.anchored = 1//Anchors them so they can't move.
+ M.captured = 1
U.say("Get over here!")
var/obj/effect/energy_net/E = new /obj/effect/energy_net(M.loc)
E.layer = M.layer+1//To have it appear one layer above the mob.
@@ -210,7 +211,7 @@ Must right click on a mob to activate.*/
E.master = U
spawn(0)//Parallel processing.
E.process(M)
- cell.use(C*100) // Nets now cost what should be most of a standard battery, since your taking someone out of the round
+ cell.use(C*10) // Nets now cost what should be most of a standard battery, since your taking someone out of the round
else
U << "They are already trapped inside an energy net."
else
diff --git a/code/game/gamemodes/events/ninja_equipment.dm b/code/game/gamemodes/events/ninja_equipment.dm
index d25dabe21bb..d2bd2dbc7b4 100644
--- a/code/game/gamemodes/events/ninja_equipment.dm
+++ b/code/game/gamemodes/events/ninja_equipment.dm
@@ -1385,7 +1385,8 @@ It is possible to destroy the net by the occupant or someone else.
if(!isnull(master))//As long as they still exist.
master << "\blue SUCCESS: \black transport procedure of \the [affecting] complete."
- M.anchored = 0//Important.
+ M.captured = 0 //Important.
+ M.anchored = initial(M.anchored) //Changes the mob's anchored status to the original one; this is not handled by the can_move proc.
else//And they are free.
M << "\blue You are free of the net!"
diff --git a/code/game/gamemodes/events/power_failure.dm b/code/game/gamemodes/events/power_failure.dm
index c8848cd3ee8..dbebc649f53 100644
--- a/code/game/gamemodes/events/power_failure.dm
+++ b/code/game/gamemodes/events/power_failure.dm
@@ -61,7 +61,7 @@
if(C.cell && C.z == 1)
C.cell.charge = C.cell.maxcharge
for(var/obj/machinery/power/smes/S in world)
- if(S.z != 1)
+ if(istype(get_area(S), /area/turret_protected) || S.z != 1)
continue
S.charge = S.last_charge
S.output = S.last_output
diff --git a/code/game/gamemodes/events/space_ninja.dm b/code/game/gamemodes/events/space_ninja.dm
index c3b77d5f875..4d0df9c3f7f 100644
--- a/code/game/gamemodes/events/space_ninja.dm
+++ b/code/game/gamemodes/events/space_ninja.dm
@@ -547,7 +547,7 @@ As such, it's hard-coded for now. No reason for it not to be, really.
equip_to_slot_or_del(new /obj/item/device/flashlight(src), slot_belt)
equip_to_slot_or_del(new /obj/item/weapon/plastique(src), slot_r_store)
equip_to_slot_or_del(new /obj/item/weapon/plastique(src), slot_l_store)
- equip_to_slot_or_del(new /obj/item/weapon/tank/emergency_oxygen(src), slot_s_store)
+ equip_to_slot_or_del(new /obj/item/weapon/tank/oxygen(src), slot_s_store)
return 1
//=======//HELPER PROCS//=======//
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index 39be77978ee..26497410fa8 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -213,7 +213,7 @@ Implants;
for(var/mob/living/carbon/human/man in player_list) if(man.client && man.mind)
// NT relation option
var/special_role = man.mind.special_role
- if (special_role == "Wizard" || special_role == "Ninja" || special_role == "Syndicate")
+ if (special_role == "Wizard" || special_role == "Ninja" || special_role == "Syndicate" || special_role == "Vox Raider")
continue //NT intelligence ruled out possiblity that those are too classy to pretend to be a crew.
if(man.client.prefs.nanotrasen_relation == "Opposed" && prob(50) || \
man.client.prefs.nanotrasen_relation == "Skeptical" && prob(20))
diff --git a/code/game/gamemodes/gameticker.dm b/code/game/gamemodes/gameticker.dm
index ea9fbaec4a7..a834a3cc0b3 100644
--- a/code/game/gamemodes/gameticker.dm
+++ b/code/game/gamemodes/gameticker.dm
@@ -118,6 +118,7 @@ var/global/datum/controller/gameticker/ticker
data_core.manifest()
current_state = GAME_STATE_PLAYING
+ callHook("roundstart")
//here to initialize the random events nicely at round start
setup_economy()
@@ -309,6 +310,8 @@ var/global/datum/controller/gameticker/ticker
declare_completion()
spawn(50)
+ callHook("roundend")
+
if (mode.station_was_nuked)
feedback_set_details("end_proper","nuke")
if(!delay_end)
diff --git a/code/game/gamemodes/heist/heist.dm b/code/game/gamemodes/heist/heist.dm
index e98d128559f..fd2cdf88ade 100644
--- a/code/game/gamemodes/heist/heist.dm
+++ b/code/game/gamemodes/heist/heist.dm
@@ -2,11 +2,6 @@
VOX HEIST ROUNDTYPE
*/
-#define MAX_VOX_KILLS 10 //Number of kills during the round before the Inviolate is broken.
- //Would be nice to use vox-specific kills but is currently not feasible.
-
-var/global/vox_kills = 0 //Used to check the Inviolate.
-
/datum/game_mode/
var/list/datum/mind/raiders = list() //Antags.
@@ -139,10 +134,8 @@ var/global/vox_kills = 0 //Used to check the Inviolate.
/datum/game_mode/heist/proc/forge_vox_objectives()
-
- //Commented out for testing.
- /* var/i = 1
- var/max_objectives = pick(2,2,2,3,3)
+ var/i = 1
+ var/max_objectives = pick(2,2,2,2,3,3,3,4)
var/list/objs = list()
while(i<= max_objectives)
var/list/goals = list("kidnap","loot","salvage")
@@ -163,24 +156,16 @@ var/global/vox_kills = 0 //Used to check the Inviolate.
//-All- vox raids have these two objectives. Failing them loses the game.
objs += new /datum/objective/heist/inviolate_crew
- objs += new /datum/objective/heist/inviolate_death */
+ objs += new /datum/objective/heist/inviolate_death
- raid_objectives += new /datum/objective/heist/kidnap
- raid_objectives += new /datum/objective/heist/loot
- raid_objectives += new /datum/objective/heist/salvage
- raid_objectives += new /datum/objective/heist/inviolate_crew
- raid_objectives += new /datum/objective/heist/inviolate_death
-
- for(var/datum/objective/heist/O in raid_objectives)
- O.choose_target()
-
- return raid_objectives
+ return objs
/datum/game_mode/heist/proc/greet_vox(var/datum/mind/raider)
raider.current << "\blue You are a Vox Raider, fresh from the Shoal!"
raider.current << "\blue The Vox are a race of cunning, sharp-eyed nomadic raiders and traders endemic to Tau Ceti and much of the unexplored galaxy. You and the crew have come to the Exodus for plunder, trade or both."
raider.current << "\blue Vox are cowardly and will flee from larger groups, but corner one or find them en masse and they are vicious."
raider.current << "\blue Use :V to voxtalk, :H to talk on your encrypted channel, and don't forget to turn on your nitrogen internals!"
+ raider.current << "\red IF YOU HAVE NOT PLAYED A VOX BEFORE, REVIEW THIS THREAD: http://baystation12.net/forums/viewtopic.php?f=6&t=8657."
var/obj_count = 1
for(var/datum/objective/objective in raider.objectives)
raider.current << "Objective #[obj_count]: [objective.explanation_text]"
diff --git a/code/game/gamemodes/meteor/meteor.dm b/code/game/gamemodes/meteor/meteor.dm
index deb28d76893..712512bd479 100644
--- a/code/game/gamemodes/meteor/meteor.dm
+++ b/code/game/gamemodes/meteor/meteor.dm
@@ -6,6 +6,7 @@
var/const/meteordelay = 2000
var/nometeors = 1
required_players = 0
+ votable = 0
uplink_welcome = "EVIL METEOR Uplink Console:"
uplink_uses = 10
diff --git a/code/game/gamemodes/meteor/meteors.dm b/code/game/gamemodes/meteor/meteors.dm
index c3720275ee2..55191067e10 100644
--- a/code/game/gamemodes/meteor/meteors.dm
+++ b/code/game/gamemodes/meteor/meteors.dm
@@ -1,5 +1,3 @@
-#define METEOR_TEMPERATURE
-
/var/const/meteor_wave_delay = 625 //minimum wait between waves in tenths of seconds
//set to at least 100 unless you want evarr ruining every round
@@ -95,18 +93,9 @@
icon_state = "smallf"
pass_flags = PASSTABLE | PASSGRILLE
-/obj/effect/meteor/Move()
- var/turf/T = src.loc
- if (istype(T, /turf))
- T.hotspot_expose(METEOR_TEMPERATURE, 1000)
- ..()
- return
-
/obj/effect/meteor/Bump(atom/A)
spawn(0)
- for(var/mob/M in range(10, src))
- if(!M.stat && !istype(M, /mob/living/silicon/ai)) //bad idea to shake an ai's view
- shake_camera(M, 3, 1)
+
if (A)
A.meteorhit(src)
playsound(src.loc, 'sound/effects/meteorimpact.ogg', 40, 1)
@@ -117,9 +106,7 @@
if(!istype(A,/obj/machinery/power/emitter) && \
!istype(A,/obj/machinery/field_generator) && \
prob(15))
-
explosion(src.loc, 4, 5, 6, 7, 0)
- playsound(src.loc, "explosion", 50, 1)
del(src)
return
@@ -146,16 +133,18 @@
if(--src.hits <= 0)
del(src) //Dont blow up singularity containment if we get stuck there.
- for(var/mob/M in range(10, src))
- if(!M.stat && !istype(M, /mob/living/silicon/ai)) //bad idea to shake an ai's view
- shake_camera(M, 3, 1)
if (A)
+ for(var/mob/M in player_list)
+ var/turf/T = get_turf(M)
+ if(!T || T.z != src.z)
+ continue
+ shake_camera(M, 3, get_dist(M.loc, src.loc) > 20 ? 1 : 3)
+ playsound(src.loc, 'sound/effects/meteorimpact.ogg', 40, 1)
explosion(src.loc, 0, 1, 2, 3, 0)
- playsound(src.loc, 'sound/effects/meteorimpact.ogg', 40, 1)
+
if (--src.hits <= 0)
if(prob(15) && !istype(A, /obj/structure/grille))
explosion(src.loc, 1, 2, 3, 4, 0)
- playsound(src.loc, "explosion", 50, 1)
del(src)
return
diff --git a/code/game/gamemodes/ninja/ninja.dm b/code/game/gamemodes/ninja/ninja.dm
index 8dd3c45e19d..ac2ab258bf3 100644
--- a/code/game/gamemodes/ninja/ninja.dm
+++ b/code/game/gamemodes/ninja/ninja.dm
@@ -26,18 +26,22 @@
ninja.assigned_role = "MODE" //So they aren't chosen for other jobs.
ninja.special_role = "Ninja"
ninja.original = ninja.current
- if(ninjastart.len == 0)
+
+ /*if(ninjastart.len == 0)
ninja.current << "\red A proper starting location for you could not be found, please report this bug!"
- ninja.current << "\red Attempting to place at a carpspawn."
- for(var/obj/effect/landmark/L in landmarks_list)
- if(L.name == "carpspawn")
- ninjastart.Add(L)
- if(ninjastart.len == 0 && latejoin.len > 0)
- ninja.current << "\red Still no spawneable locations could be found. Defaulting to latejoin."
- return 1
- else if (ninjastart.len == 0)
- ninja.current << "\red Still no spawneable locations could be found. Aborting."
- return 0
+ ninja.current << "\red Attempting to place at a carpspawn."*/
+
+ //Until such a time as people want to place ninja spawn points, carpspawn will do fine.
+ for(var/obj/effect/landmark/L in landmarks_list)
+ if(L.name == "carpspawn")
+ ninjastart.Add(L)
+ if(ninjastart.len == 0 && latejoin.len > 0)
+ ninja.current << "\red No spawneable locations could be found. Defaulting to latejoin."
+ return 1
+ else if (ninjastart.len == 0)
+ ninja.current << "\red No spawneable locations could be found. Aborting."
+ return 0
+
return 1
/datum/game_mode/ninja/pre_setup()
@@ -50,7 +54,7 @@
/datum/game_mode/ninja/post_setup()
for(var/datum/mind/ninja in ninjas)
if(ninja.current && !(istype(ninja.current,/mob/living/carbon/human))) return 0
- //forge_ninja_objectives(ninja)
+ forge_ninja_objectives(ninja)
var/mob/living/carbon/human/N = ninja.current
N.internal = N.s_store
N.internals.icon_state = "internal1"
@@ -78,7 +82,8 @@
return 1
/datum/game_mode/ninja/proc/forge_ninja_objectives(var/datum/mind/ninja)
- var/objective_list[] = list(1,2,3,4,5)
+
+ var/objective_list = list(1,2,3,4,5)
for(var/i=rand(2,4),i>0,i--)
switch(pick(objective_list))
if(1)//Kill
@@ -123,6 +128,7 @@
var/datum/objective/survive/ninja_objective = new
ninja_objective.owner = ninja
ninja.objectives += ninja_objective
+ ninja.current.mind = ninja
var/directive = generate_ninja_directive("heel")//Only hired by antags, not NT
ninja.current << "You are an elite mercenary assassin of the Spider Clan, [ninja.current.real_name]. You have a variety of abilities at your disposal, thanks to your nano-enhanced cyber armor.\nYour current directive is: \red [directive]\n \blue Try your best to adhere to this."
diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm
index be688554147..595dfe02264 100644
--- a/code/game/gamemodes/nuclear/nuclear.dm
+++ b/code/game/gamemodes/nuclear/nuclear.dm
@@ -5,9 +5,9 @@
/datum/game_mode/nuclear
name = "nuclear emergency"
config_tag = "nuclear"
- required_players = 6
+ required_players = 15
required_players_secret = 25 // 25 players - 5 players to be the nuke ops = 20 players remaining
- required_enemies = 5
+ required_enemies = 1
recommended_enemies = 5
uplink_welcome = "Corporate Backed Uplink Console:"
@@ -34,17 +34,25 @@
var/list/possible_syndicates = get_players_for_role(BE_OPERATIVE)
var/agent_number = 0
+ /*
+ * if(possible_syndicates.len > agents_possible)
+ * agent_number = agents_possible
+ * else
+ * agent_number = possible_syndicates.len
+ *
+ * if(agent_number > n_players)
+ * agent_number = n_players/2
+ */
+
if(possible_syndicates.len < 1)
return 0
- if(possible_syndicates.len > agents_possible)
- agent_number = agents_possible
- else
- agent_number = possible_syndicates.len
-
+ //Antag number should scale to active crew.
var/n_players = num_players()
- if(agent_number > n_players)
- agent_number = n_players/2
+ agent_number = Clamp((n_players/5), 2, 6)
+
+ if(possible_syndicates.len < agent_number)
+ agent_number = possible_syndicates.len
while(agent_number > 0)
var/datum/mind/new_syndicate = pick(possible_syndicates)
@@ -121,7 +129,6 @@
var/nuke_code = "[rand(10000, 99999)]"
var/leader_selected = 0
- var/agent_number = 1
var/spawnpos = 1
for(var/datum/mind/synd_mind in syndicates)
@@ -129,6 +136,10 @@
spawnpos = 1
synd_mind.current.loc = synd_spawn[spawnpos]
+ synd_mind.current.real_name = "[syndicate_name()] Operative" // placeholder while we get their actual name
+ spawn(0)
+ NukeNameAssign(synd_mind)
+
forge_syndicate_objectives(synd_mind)
greet_syndicate(synd_mind)
equip_syndicate(synd_mind.current)
@@ -136,9 +147,7 @@
if(!leader_selected)
prepare_syndicate_leader(synd_mind, nuke_code)
leader_selected = 1
- else
- synd_mind.current.real_name = "[syndicate_name()] Operative #[agent_number]"
- agent_number++
+
spawnpos++
update_synd_icons_added(synd_mind)
@@ -157,10 +166,6 @@
/datum/game_mode/proc/prepare_syndicate_leader(var/datum/mind/synd_mind, var/nuke_code)
-// var/leader_title = pick("Czar", "Boss", "Commander", "Chief", "Kingpin", "Director", "Overlord")
- spawn(1)
-// NukeNameAssign(nukelastname(synd_mind.current),syndicates) //allows time for the rest of the syndies to be chosen
- synd_mind.current.real_name = "[pick(first_names_male)] [pick(last_names)]"
if (nuke_code)
synd_mind.store_memory("Syndicate Nuclear Bomb Code: [nuke_code]", 0, 0)
synd_mind.current << "The nuclear authorization code is: [nuke_code]"
@@ -209,9 +214,7 @@
synd_mob.equip_to_slot_or_del(new /obj/item/clothing/under/syndicate(synd_mob), slot_w_uniform)
synd_mob.equip_to_slot_or_del(new /obj/item/clothing/shoes/black(synd_mob), slot_shoes)
- synd_mob.equip_to_slot_or_del(new /obj/item/clothing/suit/armor/vest(synd_mob), slot_wear_suit)
synd_mob.equip_to_slot_or_del(new /obj/item/clothing/gloves/swat(synd_mob), slot_gloves)
- synd_mob.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/swat(synd_mob), slot_head)
synd_mob.equip_to_slot_or_del(new /obj/item/weapon/card/id/syndicate(synd_mob), slot_wear_id)
if(synd_mob.backbag == 2) synd_mob.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(synd_mob), slot_back)
if(synd_mob.backbag == 3) synd_mob.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_norm(synd_mob), slot_back)
@@ -221,6 +224,26 @@
synd_mob.equip_to_slot_or_del(new /obj/item/weapon/reagent_containers/pill/cyanide(synd_mob), slot_in_backpack)
synd_mob.equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/automatic/c20r(synd_mob), slot_belt)
synd_mob.equip_to_slot_or_del(new /obj/item/weapon/storage/box/engineer(synd_mob.back), slot_in_backpack)
+
+ if(synd_mob.species)
+ var/race = synd_mob.species.name
+
+ if(race == "Unathi")
+ synd_mob.equip_to_slot_or_del(new /obj/item/clothing/suit/space/rig/syndi/unathi(synd_mob), slot_wear_suit)
+ synd_mob.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/rig/syndi/unathi(synd_mob), slot_head)
+ else if(race == "Tajaran")
+ synd_mob.equip_to_slot_or_del(new /obj/item/clothing/suit/space/rig/syndi/tajara(synd_mob), slot_wear_suit)
+ synd_mob.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/rig/syndi/tajara(synd_mob), slot_head)
+ else if(race == "Skrell")
+ synd_mob.equip_to_slot_or_del(new /obj/item/clothing/suit/space/rig/syndi/skrell(synd_mob), slot_wear_suit)
+ synd_mob.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/rig/syndi/skrell(synd_mob), slot_head)
+ else
+ synd_mob.equip_to_slot_or_del(new /obj/item/clothing/suit/space/rig/syndi/human(synd_mob), slot_wear_suit)
+ synd_mob.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/rig/syndi/human(synd_mob), slot_head)
+ else
+ synd_mob.equip_to_slot_or_del(new /obj/item/clothing/suit/space/rig/syndi/human(synd_mob), slot_wear_suit)
+ synd_mob.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/rig/syndi/human(synd_mob), slot_head)
+
var/obj/item/weapon/implant/explosive/E = new/obj/item/weapon/implant/explosive(synd_mob)
E.imp_in = synd_mob
E.implanted = 1
@@ -344,12 +367,14 @@
return newname
*/
-/proc/NukeNameAssign(var/lastname,var/list/syndicates)
- for(var/datum/mind/synd_mind in syndicates)
- switch(synd_mind.current.gender)
- if(MALE)
- synd_mind.name = "[pick(first_names_male)] [pick(last_names)]"
- if(FEMALE)
- synd_mind.name = "[pick(first_names_female)] [pick(last_names)]"
- synd_mind.current.real_name = synd_mind.name
- return
\ No newline at end of file
+
+/proc/NukeNameAssign(var/datum/mind/synd_mind)
+ var/choose_name = input(synd_mind.current, "You are a [syndicate_name()] agent! What is your name?", "Choose a name") as text
+
+ if(!choose_name)
+ return
+
+ else
+ synd_mind.current.name = choose_name
+ synd_mind.current.real_name = choose_name
+ return
\ No newline at end of file
diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm
index 5d770346d5e..a58e8b553ff 100644
--- a/code/game/gamemodes/nuclear/nuclearbomb.dm
+++ b/code/game/gamemodes/nuclear/nuclearbomb.dm
@@ -8,6 +8,8 @@ var/bomb_set
density = 1
var/deployable = 0.0
var/extended = 0.0
+ var/lighthack = 0
+ var/opened = 0.0
var/timeleft = 60.0
var/timing = 0.0
var/r_code = "ADMIN"
@@ -15,15 +17,36 @@ var/bomb_set
var/yes_code = 0.0
var/safety = 1.0
var/obj/item/weapon/disk/nuclear/auth = null
+ var/list/wires = list()
+ var/light_wire
+ var/safety_wire
+ var/timing_wire
var/removal_stage = 0 // 0 is no removal, 1 is covers removed, 2 is covers open,
// 3 is sealant open, 4 is unwrenched, 5 is removed from bolts.
flags = FPRINT
use_power = 0
+
+
/obj/machinery/nuclearbomb/New()
..()
r_code = "[rand(10000, 99999.0)]"//Creates a random code upon object spawn.
+ src.wires["Red"] = 0
+ src.wires["Blue"] = 0
+ src.wires["Green"] = 0
+ src.wires["Marigold"] = 0
+ src.wires["Fuschia"] = 0
+ src.wires["Black"] = 0
+ src.wires["Pearl"] = 0
+ var/list/w = list("Red","Blue","Green","Marigold","Black","Fuschia","Pearl")
+ src.light_wire = pick(w)
+ w -= src.light_wire
+ src.timing_wire = pick(w)
+ w -= src.timing_wire
+ src.safety_wire = pick(w)
+ w -= src.safety_wire
+
/obj/machinery/nuclearbomb/process()
if (src.timing)
bomb_set = 1 //So long as there is one nuke timing, it means one nuke is armed.
@@ -36,6 +59,34 @@ var/bomb_set
return
/obj/machinery/nuclearbomb/attackby(obj/item/weapon/O as obj, mob/user as mob)
+
+ if (istype(O, /obj/item/weapon/screwdriver))
+ src.add_fingerprint(user)
+ if (src.auth)
+ if (src.opened == 0)
+ src.opened = 1
+ overlays += image(icon, "npanel_open")
+ user << "You unscrew the control panel of [src]."
+
+ else
+ src.opened = 0
+ overlays -= image(icon, "npanel_open")
+ user << "You screw the control panel of [src] back on."
+ else
+ if (src.opened == 0)
+ user << "The [src] emits a buzzing noise, the panel staying locked in."
+ if (src.opened == 1)
+ src.opened = 0
+ overlays -= image(icon, "npanel_open")
+ user << "You screw the control panel of [src] back on."
+ flick("nuclearbombc", src)
+
+ return
+ if (istype(O, /obj/item/weapon/wirecutters) || istype(O, /obj/item/device/multitool))
+ if (src.opened == 1)
+ nukehack_win(user)
+ return
+
if (src.extended)
if (istype(O, /obj/item/weapon/disk/nuclear))
usr.drop_item()
@@ -119,11 +170,13 @@ var/bomb_set
/obj/machinery/nuclearbomb/attack_hand(mob/user as mob)
if (src.extended)
-
if (!ishuman(user))
usr << "\red You don't have the dexterity to do this!"
return 1
+ if (!ishuman(user))
+ usr << "\red You don't have the dexterity to do this!"
+ return 1
user.set_machine(src)
var/dat = text("Nuclear Fission Explosive \nAuth. Disk: []", src, (src.auth ? "++++++++++" : "----------"))
if (src.auth)
@@ -150,11 +203,23 @@ var/bomb_set
visible_message("\red With a steely snap, bolts slide out of [src] and anchor it to the flooring!")
else
visible_message("\red \The [src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.")
- flick("nuclearbombc", src)
- src.icon_state = "nuclearbomb1"
+ if(!src.lighthack)
+ flick("nuclearbombc", src)
+ src.icon_state = "nuclearbomb1"
src.extended = 1
return
+obj/machinery/nuclearbomb/proc/nukehack_win(mob/user as mob)
+ var/dat as text
+ dat += "Nuclear Fission Explosive \nNuclear Device Wires:"
+ for(var/wire in src.wires)
+ dat += text("[wire] Wire: [src.wires[wire] ? "Mend" : "Cut"]Pulse ")
+ dat += text("The device is [src.timing ? "shaking!" : "still"] ")
+ dat += text("The device is [src.safety ? "quiet" : "whirring"]. ")
+ dat += text("The lights are [src.lighthack ? "static" : "functional"]. ")
+ user << browse("Bomb Defusion[dat]","window=nukebomb_hack")
+ onclose(user, "nukebomb_hack")
+
/obj/machinery/nuclearbomb/verb/make_deployable()
set category = "Object"
set name = "Make Deployable"
@@ -172,16 +237,57 @@ var/bomb_set
else
usr << "\red You adjust some panels to make [src] deployable."
src.deployable = 1
+ return
+
/obj/machinery/nuclearbomb/Topic(href, href_list)
..()
if (!usr.canmove || usr.stat || usr.restrained())
return
- if (!ishuman(usr))
- usr << "\red You don't have the dexterity to do this!"
- return 1
if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))))
usr.set_machine(src)
+ if(href_list["act"])
+ var/temp_wire = href_list["wire"]
+ if(href_list["act"] == "pulse")
+ if (!istype(usr.get_active_hand(), /obj/item/device/multitool))
+ usr << "You need a multitool!"
+ else
+ if(src.wires[temp_wire])
+ usr << "You can't pulse a cut wire."
+ else
+ if(src.light_wire == temp_wire)
+ src.lighthack = !src.lighthack
+ spawn(100) src.lighthack = !src.lighthack
+ if(src.timing_wire == temp_wire)
+ if(src.timing)
+ explode()
+ if(src.safety_wire == temp_wire)
+ src.safety = !src.safety
+ spawn(100) src.safety = !src.safety
+ if(src.safety == 1)
+ visible_message("\blue The [src] quiets down.")
+ if(!src.lighthack)
+ if (src.icon_state == "nuclearbomb2")
+ src.icon_state = "nuclearbomb1"
+ else
+ visible_message("\blue The [src] emits a quiet whirling noise!")
+ if(href_list["act"] == "wire")
+ if (!istype(usr.get_active_hand(), /obj/item/weapon/wirecutters))
+ usr << "You need wirecutters!"
+ else
+ wires[temp_wire] = !wires[temp_wire]
+ if(src.safety_wire == temp_wire)
+ if(src.timing)
+ explode()
+ if(src.timing_wire == temp_wire)
+ if(!src.lighthack)
+ if (src.icon_state == "nuclearbomb2")
+ src.icon_state = "nuclearbomb1"
+ src.timing = 0
+ bomb_set = 0
+ if(src.light_wire == temp_wire)
+ src.lighthack = !src.lighthack
+
if (href_list["auth"])
if (src.auth)
src.auth.loc = src.loc
@@ -222,14 +328,16 @@ var/bomb_set
return
src.timing = !( src.timing )
if (src.timing)
- src.icon_state = "nuclearbomb2"
+ if(!src.lighthack)
+ src.icon_state = "nuclearbomb2"
if(!src.safety)
bomb_set = 1//There can still be issues with this reseting when there are multiple bombs. Not a big deal tho for Nuke/N
else
bomb_set = 0
else
- src.icon_state = "nuclearbomb1"
bomb_set = 0
+ if(!src.lighthack)
+ src.icon_state = "nuclearbomb1"
if (href_list["safety"])
src.safety = !( src.safety )
if(safety)
@@ -277,7 +385,8 @@ var/bomb_set
src.timing = -1.0
src.yes_code = 0
src.safety = 1
- src.icon_state = "nuclearbomb3"
+ if(!src.lighthack)
+ src.icon_state = "nuclearbomb3"
playsound(src,'sound/machines/Alarm.ogg',100,0,5)
if (ticker && ticker.mode)
ticker.mode.explosion_in_progress = 1
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index 12ac5447842..b3493efcbae 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -1,4 +1,5 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
+var/global/list/all_objectives = list()
datum/objective
var/datum/mind/owner = null //Who owns the objective.
@@ -8,9 +9,14 @@ datum/objective
var/completed = 0 //currently only used for custom objectives.
New(var/text)
+ all_objectives |= src
if(text)
explanation_text = text
+ Del()
+ all_objectives -= src
+ ..()
+
proc/check_completion()
return completed
@@ -916,8 +922,12 @@ datum/objective/heist/inviolate_crew
if(H.is_raider_crew_safe()) return 1
return 0
+#define MAX_VOX_KILLS 10 //Number of kills during the round before the Inviolate is broken.
+ //Would be nice to use vox-specific kills but is currently not feasible.
+var/global/vox_kills = 0 //Used to check the Inviolate.
+
datum/objective/heist/inviolate_death
explanation_text = "Follow the Inviolate. Minimise death and loss of resources."
check_completion()
- if(vox_kills>5) return 0
+ if(vox_kills > MAX_VOX_KILLS) return 0
return 1
\ No newline at end of file
diff --git a/code/game/gamemodes/revolution/rp_revolution.dm b/code/game/gamemodes/revolution/rp_revolution.dm
index d00b58d23b4..98f97cf4600 100644
--- a/code/game/gamemodes/revolution/rp_revolution.dm
+++ b/code/game/gamemodes/revolution/rp_revolution.dm
@@ -156,9 +156,17 @@
return 1
-/mob/living/carbon/human/proc/RevConvert(mob/M as mob in oview(src))
+/mob/living/carbon/human/proc/RevConvert()
set name = "Rev-Convert"
set category = "IC"
+ var/list/Possible = list()
+ for (var/mob/living/carbon/human/P in oview(src))
+ if(!stat && P.client && P.mind && !P.mind.special_role)
+ Possible += P
+ if(!Possible.len)
+ src << "\red There doesn't appear to be anyone available for you to convert here."
+ return
+ var/mob/living/carbon/human/M = input("Select a person to convert", "Viva la revolution!", null) as mob in Possible
if(((src.mind in ticker.mode:head_revolutionaries) || (src.mind in ticker.mode:revolutionaries)))
if((M.mind in ticker.mode:head_revolutionaries) || (M.mind in ticker.mode:revolutionaries))
src << "\red [M] is already be a revolutionary!"
@@ -251,4 +259,4 @@
rev_obj.target = M.mind
rev_obj.explanation_text = "Assassinate, convert or capture [M.real_name], the [M.mind.assigned_role]."
rev_mind.objectives += rev_obj
- rev_mind.current << "\red A new Head of Staff, [M.real_name], the [M.mind.assigned_role] has appeared. Your objectives have been updated."
\ No newline at end of file
+ rev_mind.current << "\red A new Head of Staff, [M.real_name], the [M.mind.assigned_role] has appeared. Your objectives have been updated."
diff --git a/code/game/gamemodes/setupgame.dm b/code/game/gamemodes/setupgame.dm
index 53d90a7e98c..813bbbabf2c 100644
--- a/code/game/gamemodes/setupgame.dm
+++ b/code/game/gamemodes/setupgame.dm
@@ -1,10 +1,27 @@
+/////////////////////////
+// (mostly) DNA2 SETUP
+/////////////////////////
+
+// Randomize block, assign a reference name, and optionally define difficulty (by making activation zone smaller or bigger)
+// The name is used on /vg/ for species with predefined genetic traits,
+// and for the DNA panel in the player panel.
+/proc/getAssignedBlock(var/name,var/list/blocksLeft, var/activity_bounds=DNA_DEFAULT_BOUNDS)
+ var/assigned = pick(blocksLeft)
+ blocksLeft.Remove(assigned)
+ assigned_blocks[assigned]=name
+ dna_activity_bounds[assigned]=activity_bounds
+ //testing("[name] assigned to block #[assigned].")
+ return assigned
+
/proc/setupgenetics()
if (prob(50))
+ // Currently unused. Will revisit. - N3X
BLOCKADD = rand(-300,300)
if (prob(75))
DIFFMUT = rand(0,20)
+ /* Old, for reference (so I don't accidentally activate something) - N3X
var/list/avnums = new/list()
var/tempnum
@@ -41,11 +58,62 @@
tempnum = pick(avnums)
avnums.Remove(tempnum)
BLINDBLOCK = tempnum
+ */
+ var/list/numsToAssign=new()
+ for(var/i=1;iThis being is corrupted by an alien intelligence and cannot be soul trapped."
+ return..()
+
M.attack_log += text("\[[time_stamp()]\] Has had their soul captured with [src.name] by [user.name] ([user.ckey])")
user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to capture the soul of [M.name] ([M.ckey])")
msg_admin_attack("[user.name] ([user.ckey]) used the [src.name] to capture the soul of [M.name] ([M.ckey]) (JMP)")
diff --git a/code/game/jobs/job/civilian_chaplain.dm b/code/game/jobs/job/civilian_chaplain.dm
index 84360efe58b..d7b4b1f96ca 100644
--- a/code/game/jobs/job/civilian_chaplain.dm
+++ b/code/game/jobs/job/civilian_chaplain.dm
@@ -51,9 +51,9 @@
B.name = "Toolbox Manifesto"
if("homosexuality")
B.name = "Guys Gone Wild"
- if("lol", "wtf", "gay", "penis", "ass", "poo", "badmin", "shitmin", "deadmin", "cock", "cocks")
- B.name = pick("Woodys Got Wood: The Aftermath", "War of the Cocks", "Sweet Bro and Hella Jef: Expanded Edition")
- H.setBrainLoss(100) // starts off retarded as fuck
+ //if("lol", "wtf", "gay", "penis", "ass", "poo", "badmin", "shitmin", "deadmin", "cock", "cocks")
+ // B.name = pick("Woodys Got Wood: The Aftermath", "War of the Cocks", "Sweet Bro and Hella Jef: Expanded Edition")
+ // H.setBrainLoss(100) // starts off retarded as fuck
if("science")
B.name = pick("Principle of Relativity", "Quantum Enigma: Physics Encounters Consciousness", "Programming the Universe", "Quantum Physics and Theology", "String Theory for Dummies", "How To: Build Your Own Warp Drive", "The Mysteries of Bluespace", "Playing God: Collector's Edition")
else
@@ -152,4 +152,4 @@
ticker.Bible_deity_name = B.deity_name
feedback_set_details("religion_deity","[new_deity]")
feedback_set_details("religion_book","[new_book_style]")
- return 1
\ No newline at end of file
+ return 1
diff --git a/code/game/jobs/job/medical.dm b/code/game/jobs/job/medical.dm
index 1303976b131..4f2f6596633 100644
--- a/code/game/jobs/job/medical.dm
+++ b/code/game/jobs/job/medical.dm
@@ -15,7 +15,7 @@
minimal_access = list(access_medical, access_morgue, access_genetics, access_heads,
access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce,
access_keycard_auth, access_sec_doors, access_psychiatrist)
- minimal_player_age = 7
+ minimal_player_age = 10
equip(var/mob/living/carbon/human/H)
if(!H) return 0
diff --git a/code/game/jobs/job/security.dm b/code/game/jobs/job/security.dm
index 4d0488f1229..69e9babb0ac 100644
--- a/code/game/jobs/job/security.dm
+++ b/code/game/jobs/job/security.dm
@@ -60,7 +60,7 @@
selection_color = "#ffeeee"
access = list(access_security, access_sec_doors, access_brig, access_armory, access_court, access_maint_tunnels, access_morgue)
minimal_access = list(access_security, access_sec_doors, access_brig, access_armory, access_court, access_maint_tunnels)
- minimal_player_age = 7
+ minimal_player_age = 5
equip(var/mob/living/carbon/human/H)
if(!H) return 0
@@ -100,7 +100,7 @@
access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels, access_court)
minimal_access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels, access_court)
alt_titles = list("Forensic Technician")
- minimal_player_age = 7
+ minimal_player_age = 3
equip(var/mob/living/carbon/human/H)
if(!H) return 0
H.equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_sec(H), slot_l_ear)
@@ -146,7 +146,7 @@
selection_color = "#ffeeee"
access = list(access_security, access_sec_doors, access_brig, access_court, access_maint_tunnels, access_morgue)
minimal_access = list(access_security, access_sec_doors, access_brig, access_court, access_maint_tunnels)
- minimal_player_age = 7
+ minimal_player_age = 3
equip(var/mob/living/carbon/human/H)
if(!H) return 0
H.equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_sec(H), slot_l_ear)
diff --git a/code/game/jobs/job/silicon.dm b/code/game/jobs/job/silicon.dm
index c50767d2f55..5e067d85560 100644
--- a/code/game/jobs/job/silicon.dm
+++ b/code/game/jobs/job/silicon.dm
@@ -8,7 +8,7 @@
selection_color = "#ccffcc"
supervisors = "your laws"
req_admin_notify = 1
- minimal_player_age = 30
+ minimal_player_age = 7
equip(var/mob/living/carbon/human/H)
if(!H) return 0
@@ -25,7 +25,8 @@
spawn_positions = 2
supervisors = "your laws and the AI" //Nodrak
selection_color = "#ddffdd"
- minimal_player_age = 21
+ minimal_player_age = 1
+ alt_titles = list("Android", "Robot")
equip(var/mob/living/carbon/human/H)
if(!H) return 0
diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm
index 95a6ec439b8..2330ebcb748 100644
--- a/code/game/jobs/job_controller.dm
+++ b/code/game/jobs/job_controller.dm
@@ -67,7 +67,7 @@ var/global/datum/controller/occupations/job_master
proc/FreeRole(var/rank) //making additional slot on the fly
var/datum/job/job = GetJob(rank)
- if(job && job.current_positions >= job.total_positions)
+ if(job && job.current_positions >= job.total_positions && job.total_positions != -1)
job.total_positions++
return 1
return 0
diff --git a/code/game/jobs/whitelist.dm b/code/game/jobs/whitelist.dm
index f28de56dc41..98efaf92733 100644
--- a/code/game/jobs/whitelist.dm
+++ b/code/game/jobs/whitelist.dm
@@ -2,6 +2,11 @@
var/list/whitelist = list()
+/hook/startup/proc/loadWhitelist()
+ if(config.usewhitelist)
+ load_whitelist()
+ return 1
+
/proc/load_whitelist()
whitelist = file2list(WHITELISTFILE)
if(!whitelist.len) whitelist = null
@@ -11,9 +16,14 @@ var/list/whitelist = list()
return 0
return ("[M.ckey]" in whitelist)
-var/list/alien_whitelist = list()
+/var/list/alien_whitelist = list()
-proc/load_alienwhitelist()
+/hook/startup/proc/loadAlienWhitelist()
+ if(config.usealienwhitelist)
+ load_alienwhitelist()
+ return 1
+
+/proc/load_alienwhitelist()
var/text = file2text("config/alienwhitelist.txt")
if (!text)
diary << "Failed to load config/alienwhitelist.txt\n"
diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm
index fc7202bd179..7eb8fa096e9 100644
--- a/code/game/machinery/Sleeper.dm
+++ b/code/game/machinery/Sleeper.dm
@@ -11,6 +11,13 @@
density = 1
var/orient = "LEFT" // "RIGHT" changes the dir suffix to "-r"
+
+/obj/machinery/sleep_console/process()
+ if(stat & (NOPOWER|BROKEN))
+ return
+ src.updateUsrDialog()
+ return
+
/obj/machinery/sleep_console/ex_act(severity)
switch(severity)
if(1.0)
@@ -71,10 +78,11 @@
if(occupant.reagents)
for(var/chemical in connected.available_chemicals)
dat += "[connected.available_chemicals[chemical]]: [occupant.reagents.get_reagent_amount(chemical)] units "
- dat += "Refresh meter readings each second "
+ dat += "Refresh Meter Readings "
if(src.connected.beaker)
+ dat += "Remove Beaker "
if(src.connected.filtering)
- dat += "Stop Dialysis "
+ dat += "Stop Dialysis "
dat += text("Output Beaker has [] units of free space remaining ", src.connected.beaker.reagents.maximum_volume - src.connected.beaker.reagents.total_volume)
else
dat += "Start Dialysis "
@@ -85,8 +93,10 @@
for(var/chemical in connected.available_chemicals)
dat += "Inject [connected.available_chemicals[chemical]]: "
for(var/amount in connected.amounts)
- dat += "[amount] units "
- dat += " "
+ dat += "[amount] units "
+
+
+ dat += "Eject Patient"
else
dat += "The sleeper is empty."
dat += text("
Close", user)
@@ -108,19 +118,21 @@
src.connected.inject_chemical(usr,href_list["chemical"],text2num(href_list["amount"]))
else
usr << "\red \b This person is not in good enough condition for sleepers to be effective! Use another means of treatment, such as cryogenics!"
+ src.updateUsrDialog()
if (href_list["refresh"])
src.updateUsrDialog()
+ if (href_list["removebeaker"])
+ src.connected.remove_beaker()
+ src.updateUsrDialog()
if (href_list["togglefilter"])
src.connected.toggle_filter()
src.updateUsrDialog()
+ if (href_list["ejectify"])
+ src.connected.eject()
+ src.updateUsrDialog()
src.add_fingerprint(usr)
return
-/obj/machinery/sleep_console/process()
- if(stat & (NOPOWER|BROKEN))
- return
- src.updateUsrDialog()
- return
/obj/machinery/sleep_console/power_change()
return
@@ -144,7 +156,7 @@
anchored = 1
var/orient = "LEFT" // "RIGHT" changes the dir suffix to "-r"
var/mob/living/carbon/human/occupant = null
- var/available_chemicals = list("inaprovaline" = "Inaprovaline", "stoxin" = "Soporific", "dermaline" = "Dermaline", "bicaridine" = "Bicaridine", "dexalin" = "Dexalin")
+ var/available_chemicals = list("inaprovaline" = "Inaprovaline", "stoxin" = "Soporific", "paracetamol" = "Paracetamol", "anti_toxin" = "Dylovene", "dexalin" = "Dexalin")
var/amounts = list(5, 10)
var/obj/item/weapon/reagent_containers/glass/beaker = null
var/filtering = 0
@@ -169,10 +181,9 @@
if(beaker.reagents.total_volume < beaker.reagents.maximum_volume)
src.occupant.vessel.trans_to(beaker, 1)
for(var/datum/reagent/x in src.occupant.reagents.reagent_list)
- if(x.volume > 20)
- src.occupant.reagents.trans_id_to(beaker, x.id, 2)
- src.occupant.vessel.trans_to(beaker, 1)
- src.updateDialog()
+ src.occupant.reagents.trans_to(beaker, 3)
+ src.occupant.vessel.trans_to(beaker, 1)
+ src.updateUsrDialog()
return
@@ -191,6 +202,7 @@
user.drop_item()
G.loc = src
user.visible_message("[user] adds \a [G] to \the [src]!", "You add \a [G] to \the [src]!")
+ src.updateUsrDialog()
return
else
user << "\red The sleeper has a beaker already."
diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm
index 3f17fe7299a..bd44ba4e7d2 100644
--- a/code/game/machinery/adv_med.dm
+++ b/code/game/machinery/adv_med.dm
@@ -250,6 +250,9 @@
dat += text("Paralysis Summary %: [] ([] seconds left!) ", occupant.paralysis, round(occupant.paralysis / 4))
dat += text("Body Temperature: [occupant.bodytemperature-T0C]°C ([occupant.bodytemperature*1.8-459.67]°F) ")
+ if(occupant.has_brain_worms())
+ dat += "Large growth detected in frontal lobe, possibly cancerous. Surgical removal is recommended. "
+
if(occupant.vessel)
var/blood_volume = round(occupant.vessel.get_reagent_amount("blood"))
var/blood_percent = blood_volume / 560
@@ -281,6 +284,7 @@
var/infected = ""
var/imp = ""
var/bled = ""
+ var/robot = ""
var/splint = ""
var/internal_bleeding = ""
var/lung_ruptured = ""
@@ -295,6 +299,8 @@
bled = "Bleeding:"
if(e.status & ORGAN_BROKEN)
AN = "[e.broken_description]:"
+ if(e.status & ORGAN_ROBOT)
+ robot = "Prosthetic:"
if(e.open)
open = "Open:"
var/unknown_body = 0
@@ -308,16 +314,25 @@
if(!AN && !open && !infected & !imp)
AN = "None:"
if(!(e.status & ORGAN_DESTROYED))
- dat += "
"
- for(var/datum/data/record/R in src.records)
- dat += "[R.fields["id"]]-[R.fields["name"]] "
+ for(var/datum/dna2/record/R in src.records)
+ dat += "
"
@@ -146,10 +146,11 @@
if (!src.active_record)
dat += "ERROR: Record not found."
else
- dat += " Delete Record "
- dat += "Name: [src.active_record.fields["name"]] "
-
- var/obj/item/weapon/implant/health/H = locate(src.active_record.fields["imp"])
+ dat += {" Delete Record
+ Name: [src.active_record.dna.real_name] "}
+ var/obj/item/weapon/implant/health/H = null
+ if(src.active_record.implant)
+ H=locate(src.active_record.implant)
if ((H) && (istype(H)))
dat += "Health: [H.sensehealth()] | OXY-BURN-TOX-BRUTE "
@@ -166,13 +167,13 @@
else
dat += " " //Keeping a line empty for appearances I guess.
- dat += {"UI: [src.active_record.fields["UI"]]
- SE: [src.active_record.fields["SE"]]
"}
+ dat += {"UI: [src.active_record.dna.uni_identity]
+ SE: [src.active_record.dna.struc_enzymes]
"}
if(pod1 && pod1.biomass >= CLONE_BIOMASS)
dat += {"Clone "}
else
- dat += {"Unsufficient biomass "}
+ dat += {"Insufficient biomass "}
if(4)
if (!src.active_record)
@@ -217,8 +218,8 @@
else if (href_list["view_rec"])
src.active_record = locate(href_list["view_rec"])
- if(istype(src.active_record,/datum/data/record))
- if ((isnull(src.active_record.fields["ckey"])) || (src.active_record.fields["ckey"] == ""))
+ if(istype(src.active_record,/datum/dna2/record))
+ if ((isnull(src.active_record.ckey)))
del(src.active_record)
src.temp = "ERROR: Record Corrupt"
else
@@ -248,7 +249,7 @@
else if (href_list["disk"]) //Load or eject.
switch(href_list["disk"])
if("load")
- if ((isnull(src.diskette)) || (src.diskette.data == ""))
+ if ((isnull(src.diskette)) || isnull(src.diskette.buf))
src.temp = "Load error."
src.updateUsrDialog()
return
@@ -258,12 +259,7 @@
src.updateUsrDialog()
return
- if (src.diskette.data_type == "ui")
- src.active_record.fields["UI"] = src.diskette.data
- if (src.diskette.ue)
- src.active_record.fields["name"] = src.diskette.owner
- else if (src.diskette.data_type == "se")
- src.active_record.fields["SE"] = src.diskette.data
+ src.active_record = src.diskette.buf
src.temp = "Load successful."
if("eject")
@@ -277,28 +273,24 @@
src.updateUsrDialog()
return
+ // DNA2 makes things a little simpler.
+ src.diskette.buf=src.active_record
+ src.diskette.buf.types=0
switch(href_list["save_disk"]) //Save as Ui/Ui+Ue/Se
if("ui")
- src.diskette.data = src.active_record.fields["UI"]
- src.diskette.ue = 0
- src.diskette.data_type = "ui"
+ src.diskette.buf.types=DNA2_BUF_UI
if("ue")
- src.diskette.data = src.active_record.fields["UI"]
- src.diskette.ue = 1
- src.diskette.data_type = "ui"
+ src.diskette.buf.types=DNA2_BUF_UI|DNA2_BUF_UE
if("se")
- src.diskette.data = src.active_record.fields["SE"]
- src.diskette.ue = 0
- src.diskette.data_type = "se"
- src.diskette.owner = src.active_record.fields["name"]
- src.diskette.name = "data disk - '[src.diskette.owner]'"
+ src.diskette.buf.types=DNA2_BUF_SE
+ src.diskette.name = "data disk - '[src.active_record.dna.real_name]'"
src.temp = "Save \[[href_list["save_disk"]]\] successful."
else if (href_list["refresh"])
src.updateUsrDialog()
else if (href_list["clone"])
- var/datum/data/record/C = locate(href_list["clone"])
+ var/datum/dna2/record/C = locate(href_list["clone"])
//Look for that player! They better be dead!
if(istype(C))
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
@@ -313,17 +305,17 @@
else if(!config.revival_cloning)
temp = "Error: Unable to initiate cloning cycle."
- else if(pod1.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["mrace"], C.fields["languages"]))
+ else if(pod1.growclone(C))
temp = "Initiating cloning cycle..."
records.Remove(C)
del(C)
menu = 1
else
- var/mob/selected = find_dead_player("[C.fields["ckey"]]")
+ var/mob/selected = find_dead_player("[C.ckey]")
selected << 'sound/machines/chime.ogg' //probably not the best sound but I think it's reasonable
var/answer = alert(selected,"Do you want to return to life?","Cloning","Yes","No")
- if(answer != "No" && pod1.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["mrace"], C.fields["languages"], C.fields["interface"]))
+ if(answer != "No" && pod1.growclone(C))
temp = "Initiating cloning cycle..."
records.Remove(C)
del(C)
@@ -363,27 +355,25 @@
subject.dna.check_integrity()
- var/datum/data/record/R = new /datum/data/record( )
- R.fields["mrace"] = subject.species
- R.fields["ckey"] = subject.ckey
- R.fields["name"] = subject.real_name
- R.fields["id"] = copytext(md5(subject.real_name), 2, 6)
- R.fields["UI"] = subject.dna.uni_identity
- R.fields["SE"] = subject.dna.struc_enzymes
- R.fields["languages"] = subject.languages
+ var/datum/dna2/record/R = new /datum/dna2/record()
+ R.dna=subject.dna
+ R.ckey = subject.ckey
+ R.id= copytext(md5(subject.real_name), 2, 6)
+ R.name=R.dna.real_name
+ R.types=DNA2_BUF_UI|DNA2_BUF_UE|DNA2_BUF_SE
//Add an implant if needed
var/obj/item/weapon/implant/health/imp = locate(/obj/item/weapon/implant/health, subject)
if (isnull(imp))
imp = new /obj/item/weapon/implant/health(subject)
imp.implanted = subject
- R.fields["imp"] = "\ref[imp]"
+ R.implant = "\ref[imp]"
//Update it if needed
else
- R.fields["imp"] = "\ref[imp]"
+ R.implant = "\ref[imp]"
if (!isnull(subject.mind)) //Save that mind so traitors can continue traitoring after cloning.
- R.fields["mind"] = "\ref[subject.mind]"
+ R.mind = "\ref[subject.mind]"
src.records += R
scantemp = "Subject successfully scanned."
@@ -391,8 +381,8 @@
//Find a specific record by key.
/obj/machinery/computer/cloning/proc/find_record(var/find_key)
var/selected_record = null
- for(var/datum/data/record/R in src.records)
- if (R.fields["ckey"] == find_key)
+ for(var/datum/dna2/record/R in src.records)
+ if (R.ckey == find_key)
selected_record = R
break
return selected_record
diff --git a/code/game/machinery/computer/computer.dm b/code/game/machinery/computer/computer.dm
index ae0dc3c5c36..c47eb1f9136 100644
--- a/code/game/machinery/computer/computer.dm
+++ b/code/game/machinery/computer/computer.dm
@@ -27,7 +27,7 @@
for(var/x in verbs)
verbs -= x
set_broken()
- var/datum/effect/effect/system/harmless_smoke_spread/smoke = new /datum/effect/effect/system/harmless_smoke_spread()
+ var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread()
smoke.set_up(5, 0, src)
smoke.start()
return
diff --git a/code/game/machinery/computer/message.dm b/code/game/machinery/computer/message.dm
index ed164896369..71a545cd556 100644
--- a/code/game/machinery/computer/message.dm
+++ b/code/game/machinery/computer/message.dm
@@ -443,7 +443,6 @@
//Sender isn't faking as someone who exists
if(isnull(PDARec))
src.linkedServer.send_pda_message("[customrecepient.owner]", "[customsender]","[custommessage]")
- customrecepient.tnote += "← From [customsender] ([customjob]): [custommessage] "
if (!customrecepient.silent)
playsound(customrecepient.loc, 'sound/machines/twobeep.ogg', 50, 1)
for (var/mob/O in hearers(3, customrecepient.loc))
@@ -456,8 +455,13 @@
customrecepient.overlays += image('icons/obj/pda.dmi', "pda-r")
//Sender is faking as someone who exists
else
+
src.linkedServer.send_pda_message("[customrecepient.owner]", "[PDARec.owner]","[custommessage]")
- customrecepient.tnote += "← From [PDARec.owner] ([customjob]): [custommessage] "
+ customrecepient.tnote.Add(list(list("sent" = 0, "owner" = "[PDARec.owner]", "job" = "[customjob]", "message" = "[custommessage]", "target" ="\ref[PDARec]")))
+
+ if(!customrecepient.conversations.Find("\ref[PDARec]"))
+ customrecepient.conversations.Add("\ref[PDARec]")
+
if (!customrecepient.silent)
playsound(customrecepient.loc, 'sound/machines/twobeep.ogg', 50, 1)
for (var/mob/O in hearers(3, customrecepient.loc))
diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm
index e56ba78f201..479633ff100 100644
--- a/code/game/machinery/computer/security.dm
+++ b/code/game/machinery/computer/security.dm
@@ -347,6 +347,7 @@ What a mess.*/
P.info += "
"
P.name = "paper - 'Security Record'"
printing = null
+ updateUsrDialog()
//RECORD DELETE
if ("Delete All Records")
temp = ""
diff --git a/code/game/machinery/cryo.dm b/code/game/machinery/cryo.dm
index 073c1b8fe40..b909404a1c9 100644
--- a/code/game/machinery/cryo.dm
+++ b/code/game/machinery/cryo.dm
@@ -5,7 +5,7 @@
density = 1
anchored = 1.0
layer = 2.8
-
+
var/on = 0
var/temperature_archived
var/mob/living/carbon/occupant = null
@@ -65,10 +65,10 @@
/**
* The ui_interact proc is used to open and update Nano UIs
* If ui_interact is not used then the UI will not update correctly
- * ui_interact is currently defined for /atom/movable
+ * ui_interact is currently defined for /atom/movable (which is inherited by /obj and /mob)
*
* @param user /mob The mob who is interacting with this ui
- * @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
+ * @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
* @param ui /datum/nanoui This parameter is passed by the nanoui process() proc when updating an open ui
*
* @return nothing
@@ -79,23 +79,12 @@
return
// this is the data which will be sent to the ui
- var/data[0]
+ var/data[0]
data["isOperating"] = on
data["hasOccupant"] = occupant ? 1 : 0
var/occupantData[0]
- if (!occupant)
- occupantData["name"] = null
- occupantData["stat"] = null
- occupantData["health"] = null
- occupantData["maxHealth"] = null
- occupantData["minHealth"] = null
- occupantData["bruteLoss"] = null
- occupantData["oxyLoss"] = null
- occupantData["toxLoss"] = null
- occupantData["fireLoss"] = null
- occupantData["bodyTemperature"] = null
- else
+ if (occupant)
occupantData["name"] = occupant.name
occupantData["stat"] = occupant.stat
occupantData["health"] = occupant.health
@@ -115,7 +104,7 @@
else if(air_contents.temperature > 225)
data["cellTemperatureStatus"] = "average"
- data["isBeakerLoaded"] = beaker ? 1 : 0
+ data["isBeakerLoaded"] = beaker ? 1 : 0
/* // Removing beaker contents list from front-end, replacing with a total remaining volume
var beakerContents[0]
if(beaker && beaker.reagents && beaker.reagents.reagent_list.len)
@@ -130,24 +119,19 @@
if (beaker.reagents && beaker.reagents.reagent_list.len)
for(var/datum/reagent/R in beaker.reagents.reagent_list)
data["beakerVolume"] += R.volume
-
- if (!ui) // no ui has been passed, so we'll search for one
- {
- ui = nanomanager.get_open_ui(user, src, ui_key)
- }
- if (!ui)
- // the ui does not exist, so we'll create a new one
+
+ // update the ui if it exists, returns null if no ui is passed/found
+ ui = nanomanager.try_update_ui(user, src, ui_key, ui, data)
+ if (!ui)
+ // the ui does not exist, so we'll create a new() one
+ // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "cryo.tmpl", "Cryo Cell Control System", 520, 410)
- // When the UI is first opened this is the data it will use
- ui.set_initial_data(data)
+ // when the ui is first opened this is the data it will use
+ ui.set_initial_data(data)
+ // open the new ui window
ui.open()
- // Auto update every Master Controller tick
+ // auto update every Master Controller tick
ui.set_auto_update(1)
- else
- // The UI is already open so push the new data to it
- ui.push_data(data)
- return
- //user.set_machine(src)
/obj/machinery/atmospherics/unary/cryo_cell/Topic(href, href_list)
if(usr == occupant)
@@ -159,7 +143,7 @@
if(href_list["switchOn"])
on = 1
update_icon()
-
+
if(href_list["switchOff"])
on = 0
update_icon()
@@ -168,12 +152,12 @@
if(beaker)
beaker.loc = get_step(loc, SOUTH)
beaker = null
-
+
if(href_list["ejectOccupant"])
if(!occupant || isslime(usr) || ispAI(usr))
return 0 // don't update UIs attached to this object
go_out()
-
+
add_fingerprint(usr)
return 1 // update UIs attached to this object
@@ -268,15 +252,15 @@
occupant.client.eye = occupant.client.mob
occupant.client.perspective = MOB_PERSPECTIVE
occupant.loc = get_step(loc, SOUTH) //this doesn't account for walls or anything, but i don't forsee that being a problem.
- if (occupant.bodytemperature < 261 && occupant.bodytemperature > 140) //Patch by Aranclanos to stop people from taking burn damage after being ejected
- occupant.bodytemperature = 261
+ if (occupant.bodytemperature < 261 && occupant.bodytemperature >= 70) //Patch by Aranclanos to stop people from taking burn damage after being ejected
+ occupant.bodytemperature = 261 // Changed to 70 from 140 by Zuhayr due to reoccurance of bug.
// occupant.metabslow = 0
occupant = null
update_icon()
return
/obj/machinery/atmospherics/unary/cryo_cell/proc/put_mob(mob/living/carbon/M as mob)
if (!istype(M))
- usr << "\red The cryo cell cannot handle such liveform!"
+ usr << "\red The cryo cell cannot handle such a lifeform!"
return
if (occupant)
usr << "\red The cryo cell is already occupied!"
diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm
new file mode 100644
index 00000000000..3a0de6a8006
--- /dev/null
+++ b/code/game/machinery/cryopod.dm
@@ -0,0 +1,414 @@
+/*
+ * Cryogenic refrigeration unit. Basically a despawner.
+ * Stealing a lot of concepts/code from sleepers due to massive laziness.
+ * The despawn tick will only fire if it's been more than time_till_despawned ticks
+ * since time_entered, which is world.time when the occupant moves in.
+ * ~ Zuhayr
+ */
+
+//Used for logging people entering cryosleep and important items they are carrying.
+var/global/list/frozen_crew = list()
+var/global/list/frozen_items = list()
+
+//Main cryopod console.
+
+/obj/machinery/computer/cryopod
+ name = "cryogenic oversight console"
+ desc = "An interface between crew and the cryogenic storage oversight systems."
+ icon = 'icons/obj/Cryogenic2.dmi'
+ icon_state = "cellconsole"
+ circuit = "/obj/item/weapon/circuitboard/cryopodcontrol"
+ var/mode = null
+
+/obj/machinery/computer/cryopod/attack_paw()
+ src.attack_hand()
+
+/obj/machinery/computer/cryopod/attack_ai()
+ src.attack_hand()
+
+obj/machinery/computer/cryopod/attack_hand(mob/user = usr)
+ if(stat & (NOPOWER|BROKEN))
+ return
+
+ user.set_machine(src)
+ src.add_fingerprint(usr)
+
+ var/dat
+
+ if (!( ticker ))
+ return
+
+ dat += " Cryogenic Oversight Control "
+ dat += "Welcome, [user.real_name].
"
+ dat += "View storage log. "
+ dat += "Recover object. "
+ dat += "Recover all objects. "
+ dat += "Revive crew. "
+
+ user << browse(dat, "window=cryopod_console")
+ onclose(user, "cryopod_console")
+
+obj/machinery/computer/cryopod/Topic(href, href_list)
+
+ if(..())
+ return
+
+ var/mob/user = usr
+
+ src.add_fingerprint(user)
+
+ if(href_list["log"])
+
+ var/dat = "Recently stored crewmembers "
+ for(var/person in frozen_crew)
+ dat += "[person] "
+ dat += ""
+
+ user << browse(dat, "window=cryolog")
+
+ else if(href_list["item"])
+
+ if(frozen_items.len == 0)
+ user << "\blue There is nothing to recover from storage."
+ return
+
+ var/obj/item/I = input(usr, "Please choose which object to retrieve.","Object recovery",null) as obj in frozen_items
+
+ if(!I || frozen_items.len == 0)
+ user << "\blue There is nothing to recover from storage."
+ return
+
+ visible_message("\blue The console beeps happily as it disgorges \the [I].", 3)
+
+ I.loc = get_turf(src)
+ frozen_items -= I
+
+ else if(href_list["allitems"])
+
+ if(frozen_items.len == 0)
+ user << "\blue There is nothing to recover from storage."
+ return
+
+ visible_message("\blue The console beeps happily as it disgorges the desired objects.", 3)
+
+ for(var/obj/item/I in frozen_items)
+ I.loc = get_turf(src)
+ frozen_items -= I
+
+ else if(href_list["crew"])
+ user << "\red Functionality unavailable at this time."
+
+ src.updateUsrDialog()
+ return
+
+/obj/item/weapon/circuitboard/cryopodcontrol
+ name = "Circuit board (Cryogenic Oversight Console)"
+ build_path = "/obj/machinery/computer/cryopod"
+ origin_tech = "programming=3"
+
+//Decorative structures to go alongside cryopods.
+/obj/structure/cryofeed
+
+ name = "\improper cryogenic feed"
+ desc = "A bewildering tangle of machinery and pipes."
+ icon = 'icons/obj/Cryogenic2.dmi'
+ icon_state = "cryo_rear"
+ anchored = 1
+
+ var/orient_right = null //Flips the sprite.
+
+/obj/structure/cryofeed/right
+ orient_right = 1
+ icon_state = "cryo_rear-r"
+
+/obj/structure/cryofeed/New()
+
+ if(orient_right)
+ icon_state = "cryo_rear-r"
+ else
+ icon_state = "cryo_rear"
+ ..()
+
+//Cryopods themselves.
+/obj/machinery/cryopod
+ name = "\improper cryogenic freezer"
+ desc = "A man-sized pod for entering suspended animation."
+ icon = 'icons/obj/Cryogenic2.dmi'
+ icon_state = "body_scanner_0"
+ density = 1
+ anchored = 1
+
+ var/mob/occupant = null // Person waiting to be despawned.
+ var/orient_right = null // Flips the sprite.
+ var/time_till_despawn = 9000 // 15 minutes-ish safe period before being despawned.
+ var/time_entered = 0 // Used to keep track of the safe period.
+ var/obj/item/device/radio/intercom/announce //
+
+ // These items are preserved when the process() despawn proc occurs.
+ var/list/preserve_items = list(
+ /obj/item/weapon/hand_tele,
+ /obj/item/weapon/card/id/captains_spare,
+ /obj/item/device/aicard,
+ /obj/item/device/mmi,
+ /obj/item/device/paicard,
+ /obj/item/weapon/gun,
+ /obj/item/weapon/pinpointer,
+ /obj/item/clothing/suit,
+ /obj/item/clothing/shoes/magboots,
+ /obj/item/blueprints,
+ /obj/item/clothing/head/helmet/space/
+ )
+
+/obj/machinery/cryopod/right
+ orient_right = 1
+ icon_state = "body_scanner_0-r"
+
+/obj/machinery/cryopod/New()
+
+ announce = new /obj/item/device/radio/intercom(src)
+
+ if(orient_right)
+ icon_state = "body_scanner_0-r"
+ else
+ icon_state = "body_scanner_0"
+ ..()
+
+//Lifted from Unity stasis.dm and refactored. ~Zuhayr
+/obj/machinery/cryopod/process()
+ if(occupant)
+
+ //Allow a ten minute gap between entering the pod and actually despawning.
+ if(world.time - time_entered < time_till_despawn)
+ return
+
+ if(!occupant.client && occupant.stat<2) //Occupant is living and has no client.
+
+ //Drop all items into the pod.
+ for(var/obj/item/W in occupant)
+ occupant.drop_from_inventory(W)
+ W.loc = src
+
+ if(W.contents.len) //Make sure we catch anything not handled by del() on the items.
+ for(var/obj/item/O in W.contents)
+ O.loc = src
+
+ //Delete all items not on the preservation list.
+ var/list/items = src.contents
+ items -= occupant // Don't delete the occupant
+ items -= announce // or the autosay radio.
+
+ for(var/obj/item/W in items)
+ var/preserve = null
+ for(var/T in preserve_items)
+ if(istype(W,T))
+ preserve = 1
+ break
+
+ if(!preserve)
+ del(W)
+ else
+ frozen_items += W
+
+ //Update any existing objectives involving this mob.
+ for(var/datum/objective/O in all_objectives)
+ if(istype(O,/datum/objective/mutiny)) //We don't want revs to get objectives that aren't for heads of staff. Letting them win or lose based on cryo is silly so we remove the objective.
+ del(O) //TODO: Update rev objectives on login by head (may happen already?) ~ Z
+ else if(O.target && istype(O.target,/datum/mind))
+ if(O.target == occupant.mind)
+ if(O.owner && O.owner.current)
+ O.owner.current << "\red You get the feeling your target is no longer within your reach. Time for Plan [pick(list("A","B","C","D","X","Y","Z"))]..."
+ O.target = null
+ spawn(1) //This should ideally fire after the occupant is deleted.
+ if(!O) return
+ O.find_target()
+ if(!(O.target))
+ all_objectives -= O
+ O.owner.objectives -= O
+ del(O)
+
+ //Handle job slot/tater cleanup.
+ var/job = occupant.mind.assigned_role
+
+ job_master.FreeRole(job)
+
+ if(occupant.mind.objectives.len)
+ del(occupant.mind.objectives)
+ occupant.mind.special_role = null
+ else
+ if(ticker.mode.name == "AutoTraitor")
+ var/datum/game_mode/traitor/autotraitor/current_mode = ticker.mode
+ current_mode.possible_traitors.Remove(occupant)
+
+ // Delete them from datacore.
+ for(var/datum/data/record/R in data_core.medical)
+ if ((R.fields["name"] == occupant.real_name))
+ del(R)
+ for(var/datum/data/record/T in data_core.security)
+ if ((T.fields["name"] == occupant.real_name))
+ del(T)
+ for(var/datum/data/record/G in data_core.general)
+ if ((G.fields["name"] == occupant.real_name))
+ del(G)
+
+ if(orient_right)
+ icon_state = "body_scanner_0-r"
+ else
+ icon_state = "body_scanner_0"
+
+ //TODO: Check objectives/mode, update new targets if this mob is the target, spawn new antags?
+
+ //This should guarantee that ghosts don't spawn.
+ occupant.ckey = null
+
+ //Make an announcement and log the person entering storage.
+ frozen_crew += "[occupant.real_name]"
+
+ announce.autosay("[occupant.real_name] has entered long-term storage.", "Cryogenic Oversight")
+ visible_message("\blue The crypod hums and hisses as it moves [occupant.real_name] into storage.", 3)
+
+ // Delete the mob.
+ del(occupant)
+ occupant = null
+
+
+ return
+
+
+/obj/machinery/cryopod/attackby(var/obj/item/weapon/G as obj, var/mob/user as mob)
+
+ if(istype(G, /obj/item/weapon/grab))
+
+ if(occupant)
+ user << "\blue The cryo pod is in use."
+ return
+
+ if(!ismob(G:affecting))
+ return
+
+ var/willing = null //We don't want to allow people to be forced into despawning.
+ var/mob/M = G:affecting
+
+ if(M.client)
+ if(alert(M,"Would you like to enter cryosleep?",,"Yes","No") == "Yes")
+ if(!M || !G || !G:affecting) return
+ willing = 1
+ else
+ willing = 1
+
+ if(willing)
+
+ visible_message("[user] starts putting [G:affecting:name] into the cryo pod.", 3)
+
+ if(do_after(user, 20))
+ if(!M || !G || !G:affecting) return
+
+ M.loc = src
+
+ if(M.client)
+ M.client.perspective = EYE_PERSPECTIVE
+ M.client.eye = src
+
+ if(orient_right)
+ icon_state = "body_scanner_1-r"
+ else
+ icon_state = "body_scanner_1"
+
+ M << "\blue You feel cool air surround you. You go numb as your senses turn inward."
+ M << "\blue If you ghost, log out or close your client now, your character will shortly be permanently removed from the round."
+ occupant = M
+ time_entered = world.time
+
+ // Book keeping!
+ log_admin("[key_name_admin(M)] has entered a stasis pod.")
+ message_admins("\blue [key_name_admin(M)] has entered a stasis pod.")
+
+ //Despawning occurs when process() is called with an occupant without a client.
+ src.add_fingerprint(M)
+
+/obj/machinery/cryopod/verb/eject()
+ set name = "Eject Pod"
+ set category = "Object"
+ set src in oview(1)
+ if(usr.stat != 0)
+ return
+
+ if(orient_right)
+ icon_state = "body_scanner_0-r"
+ else
+ icon_state = "body_scanner_0"
+
+ src.go_out()
+ add_fingerprint(usr)
+ return
+
+/obj/machinery/cryopod/verb/move_inside()
+ set name = "Enter Pod"
+ set category = "Object"
+ set src in oview(1)
+
+ if(usr.stat != 0 || !(ishuman(usr) || ismonkey(usr)))
+ return
+
+ if(src.occupant)
+ usr << "\blue The cryo pod is in use."
+ return
+
+ for(var/mob/living/carbon/slime/M in range(1,usr))
+ if(M.Victim == usr)
+ usr << "You're too busy getting your life sucked out of you."
+ return
+
+ visible_message("[usr] starts climbing into the cryo pod.", 3)
+
+ if(do_after(usr, 20))
+
+ if(!usr || !usr.client)
+ return
+
+ if(src.occupant)
+ usr << "\blue The cryo pod is in use."
+ return
+
+ usr.stop_pulling()
+ usr.client.perspective = EYE_PERSPECTIVE
+ usr.client.eye = src
+ usr.loc = src
+ src.occupant = usr
+
+ if(orient_right)
+ icon_state = "body_scanner_1-r"
+ else
+ icon_state = "body_scanner_1"
+
+ usr << "\blue You feel cool air surround you. You go numb as your senses turn inward."
+ usr << "\blue If you ghost, log out or close your client now, your character will shortly be permanently removed from the round."
+ occupant = usr
+ time_entered = world.time
+
+ src.add_fingerprint(usr)
+
+ return
+
+/obj/machinery/cryopod/proc/go_out()
+
+ if(!occupant)
+ return
+
+ if(occupant.client)
+ occupant.client.eye = src.occupant.client.mob
+ occupant.client.perspective = MOB_PERSPECTIVE
+
+ occupant.loc = get_turf(src)
+ occupant = null
+
+ if(orient_right)
+ icon_state = "body_scanner_0-r"
+ else
+ icon_state = "body_scanner_0"
+
+ return
+
+
+//Attacks/effects.
+/obj/machinery/cryopod/blob_act()
+ return //Sorta gamey, but we don't really want these to be destroyed.
diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm
index 47ebf869d74..3fd77b8b34b 100644
--- a/code/game/machinery/doors/firedoor.dm
+++ b/code/game/machinery/doors/firedoor.dm
@@ -88,11 +88,11 @@
user << "Access denied."
return
- var/area/A = get_area(src)
- ASSERT(istype(A))
- if(A.master)
- A = A.master
- var/alarmed = A.air_doors_activated || A.fire
+ var/alarmed = 0
+
+ for(var/area/A in areas_added) //Checks if there are fire alarms in any areas associated with that firedoor
+ if(A.fire || A.air_doors_activated)
+ alarmed = 1
var/answer = alert(user, "Would you like to [density ? "open" : "close"] this [src.name]?[ alarmed && density ? "\nNote that by doing so, you acknowledge any damages from opening this\n[src.name] as being your own fault, and you will be held accountable under the law." : ""]",\
"\The [src]", "Yes, [density ? "open" : "close"]", "No")
@@ -114,9 +114,13 @@
if(needs_to_close)
spawn(50)
+ alarmed = 0
+ for(var/area/A in areas_added) //Just in case a fire alarm is turned off while the firedoor is going through an autoclose cycle
+ if(A.fire || A.air_doors_activated)
+ alarmed = 1
if(alarmed)
nextstate = CLOSED
-
+ close()
/obj/machinery/door/firedoor/attackby(obj/item/weapon/C as obj, mob/user as mob)
add_fingerprint(user)
diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm
index 9de6b2c6aa8..303e814ef11 100644
--- a/code/game/machinery/flasher.dm
+++ b/code/game/machinery/flasher.dm
@@ -79,13 +79,15 @@
continue
O.Weaken(strength)
- if ((O.eye_stat > 15 && prob(O.eye_stat + 50)))
- flick("e_flash", O:flash)
- O.eye_stat += rand(1, 2)
+ if (istype(O, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = O
+ var/datum/organ/internal/eyes/E = H.internal_organs["eyes"]
+ if ((E.damage > E.min_bruised_damage && prob(E.damage + 50)))
+ flick("e_flash", O:flash)
+ E.damage += rand(1, 5)
else
if(!O.blinded)
flick("flash", O:flash)
- O.eye_stat += rand(0, 2)
/obj/machinery/flasher/emp_act(severity)
diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm
index 970048272aa..e677e6e8be9 100644
--- a/code/game/machinery/iv_drip.dm
+++ b/code/game/machinery/iv_drip.dm
@@ -70,6 +70,7 @@
set background = 1
if(src.attached)
+
if(!(get_dist(src, src.attached) <= 1 && isturf(src.attached.loc)))
visible_message("The needle is ripped out of [src.attached], doesn't that hurt?")
src.attached:apply_damage(3, BRUTE, pick("r_arm", "l_arm"))
@@ -105,6 +106,9 @@
if(NOCLONE in T.mutations)
return
+ if(T.species && T.species.flags & NO_BLOOD)
+ return
+
// If the human is losing too much blood, beep.
if(T.vessel.get_reagent_amount("blood") < BLOOD_VOLUME_SAFE) if(prob(5))
visible_message("\The [src] beeps loudly.")
diff --git a/code/game/machinery/kitchen/microwave.dm b/code/game/machinery/kitchen/microwave.dm
index d25e1ecc145..0c45afb4095 100644
--- a/code/game/machinery/kitchen/microwave.dm
+++ b/code/game/machinery/kitchen/microwave.dm
@@ -43,6 +43,11 @@
if (recipe.items)
max_n_of_items = max(max_n_of_items,recipe.items.len)
+ // This will do until I can think of a fun recipe to use dionaea in -
+ // will also allow anything using the holder item to be microwaved into
+ // impure carbon. ~Z
+ acceptable_items |= /obj/item/weapon/holder
+
/*******************
* Item Adding
********************/
diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm
index af52a4e7565..b1783b1707c 100644
--- a/code/game/machinery/newscaster.dm
+++ b/code/game/machinery/newscaster.dm
@@ -409,10 +409,10 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co
dat+="Wanted issue for [src.channel_name] successfully edited.
"
dat+=" Return "
if(20)
- dat+="Printing successfull. Please receive your newspaper from the bottom of the machine.
"
+ dat+="Printing successful. Please receive your newspaper from the bottom of the machine.
"
dat+="Return"
if(21)
- dat+="Unable to print newspaper. Insufficient paper. Please notify maintenance personnell to refill machine storage.
"
+ dat+="Unable to print newspaper. Insufficient paper. Please notify maintenance personnel to refill machine storage.
"
dat+="Return"
else
dat+="I'm sorry to break your immersion. This shit's bugged. Report this bug to Agouri, polyxenitopalidou@gmail.com"
diff --git a/code/game/machinery/podmen.dm b/code/game/machinery/podmen.dm
index 7654bda9641..6dd173f4478 100644
--- a/code/game/machinery/podmen.dm
+++ b/code/game/machinery/podmen.dm
@@ -92,6 +92,8 @@ Growing it to term with nothing injected will grab a ghost from the observers. *
/obj/item/seeds/replicapod/proc/request_player()
for(var/mob/dead/observer/O in player_list)
+ if(jobban_isbanned(O, "Dionaea"))
+ continue
if(O.client)
if(O.client.prefs.be_special & BE_PLANT)
question(O.client)
diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm
index 640fc00afcd..03d97e0e1f3 100644
--- a/code/game/machinery/shieldgen.dm
+++ b/code/game/machinery/shieldgen.dm
@@ -384,7 +384,7 @@
user.visible_message("[user] turned the shield generator off.", \
"You turn off the shield generator.", \
"You hear heavy droning fade out.")
- src.cleanup()
+ for(var/dir in list(1,2,4,8)) src.cleanup(dir)
else
src.active = 1
icon_state = "Shield_Gen +a"
@@ -424,14 +424,7 @@
"You hear heavy droning fade out")
icon_state = "Shield_Gen"
src.active = 0
- spawn(1)
- src.cleanup(1)
- spawn(1)
- src.cleanup(2)
- spawn(1)
- src.cleanup(4)
- spawn(1)
- src.cleanup(8)
+ for(var/dir in list(1,2,4,8)) src.cleanup(dir)
/obj/machinery/shieldwallgen/proc/setup_field(var/NSEW = 0)
var/turf/T = src.loc
diff --git a/code/game/machinery/telecomms/broadcaster.dm b/code/game/machinery/telecomms/broadcaster.dm
index d90986a5dda..7775e3aa20d 100644
--- a/code/game/machinery/telecomms/broadcaster.dm
+++ b/code/game/machinery/telecomms/broadcaster.dm
@@ -288,7 +288,10 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept
if(istype(R, /mob/new_player)) // we don't want new players to hear messages. rare but generates runtimes.
continue
-
+
+ // Ghosts hearing all radio chat don't want to hear syndicate intercepts, they're duplicates
+ if(data == 3 && istype(R, /mob/dead/observer) && R.client && (R.client.prefs.toggles & CHAT_GHOSTRADIO))
+ continue
// --- Check for compression ---
if(compression > 0)
@@ -333,19 +336,19 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept
freq_text = "#unkn"
if(COMM_FREQ)
freq_text = "Command"
- if(1351)
+ if(SCI_FREQ)
freq_text = "Science"
- if(1355)
+ if(MED_FREQ)
freq_text = "Medical"
- if(1357)
+ if(ENG_FREQ)
freq_text = "Engineering"
- if(1359)
+ if(SEC_FREQ)
freq_text = "Security"
- if(1347)
+ if(SUP_FREQ)
freq_text = "Supply"
- if(1441)
+ if(1341)
freq_text = "Special Ops"
- if(1443)
+ if(1345)
freq_text = "Response Team"
//There's probably a way to use the list var of channels in code\game\communications.dm to make the dept channels non-hardcoded, but I wasn't in an experimentive mood. --NEO
diff --git a/code/game/machinery/telecomms/presets.dm b/code/game/machinery/telecomms/presets.dm
index 914bd8c9016..83f3a532b7f 100644
--- a/code/game/machinery/telecomms/presets.dm
+++ b/code/game/machinery/telecomms/presets.dm
@@ -43,6 +43,13 @@
"supply", "common", "command", "engineering", "security",
"receiverA", "receiverB", "broadcasterA", "broadcasterB")
+/obj/machinery/telecomms/hub/preset_cent
+ id = "CentComm Hub"
+ network = "tcommsat"
+ heatgen = 0
+ autolinkers = list("hub_cent", "c_relay", "s_relay", "m_relay", "r_relay",
+ "centcomm", "receiverCent", "broadcasterCent")
+
//Receivers
//--PRESET LEFT--//
@@ -68,6 +75,13 @@
freq_listening |= i
..()
+/obj/machinery/telecomms/receiver/preset_cent
+ id = "CentComm Receiver"
+ network = "tcommsat"
+ heatgen = 0
+ autolinkers = list("receiverCent")
+ freq_listening = list(1345, 1341)
+
//Buses
@@ -100,6 +114,13 @@
freq_listening |= i
..()
+/obj/machinery/telecomms/bus/preset_cent
+ id = "CentComm Bus"
+ network = "tcommsat"
+ freq_listening = list(1345, 1341)
+ heatgen = 0
+ autolinkers = list("processorCent", "centcomm")
+
//Processors
/obj/machinery/telecomms/processor/preset_one
@@ -122,6 +143,12 @@
network = "tcommsat"
autolinkers = list("processor4")
+/obj/machinery/telecomms/processor/preset_cent
+ id = "CentComm Processor"
+ network = "tcommsat"
+ heatgen = 0
+ autolinkers = list("processorCent")
+
//Servers
/obj/machinery/telecomms/server/presets
@@ -170,6 +197,12 @@
freq_listening = list(1359)
autolinkers = list("security")
+/obj/machinery/telecomms/server/presets/centcomm
+ id = "CentComm Server"
+ freq_listening = list(1345, 1341)
+ heatgen = 0
+ autolinkers = list("centcomm")
+
//Broadcasters
@@ -186,3 +219,9 @@
id = "Broadcaster B"
network = "tcommsat"
autolinkers = list("broadcasterB")
+
+/obj/machinery/telecomms/broadcaster/preset_cent
+ id = "CentComm Broadcaster"
+ network = "tcommsat"
+ heatgen = 0
+ autolinkers = list("broadcasterCent")
\ No newline at end of file
diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm
index 1476b13d0a8..f09abfeefe0 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -52,6 +52,8 @@
var/const/WIRE_SHOCK = 3
var/const/WIRE_SHOOTINV = 4
+ var/check_accounts = 0 // 1 = requires PIN and checks accounts. 0 = You slide an ID, it vends, SPACE COMMUNISM!
+
/obj/machinery/vending/New()
..()
spawn(4)
@@ -148,6 +150,14 @@
else if(istype(W, /obj/item/weapon/card) && currently_vending)
var/obj/item/weapon/card/I = W
scan_card(I)
+
+ else if(src.panel_open)
+
+ for(var/datum/data/vending_product/R in product_records)
+ if(istype(W, R.product_path))
+ stock(R, user)
+ del(W)
+
else
..()
@@ -156,46 +166,51 @@
if (istype(I, /obj/item/weapon/card/id))
var/obj/item/weapon/card/id/C = I
visible_message("[usr] swipes a card through [src].")
- if(vendor_account)
- var/attempt_pin = input("Enter pin code", "Vendor transaction") as num
- var/datum/money_account/D = attempt_account_access(C.associated_account_number, attempt_pin, 2)
- if(D)
- var/transaction_amount = currently_vending.price
- if(transaction_amount <= D.money)
+ if(check_accounts)
+ if(vendor_account)
+ var/attempt_pin = input("Enter pin code", "Vendor transaction") as num
+ var/datum/money_account/D = attempt_account_access(C.associated_account_number, attempt_pin, 2)
+ if(D)
+ var/transaction_amount = currently_vending.price
+ if(transaction_amount <= D.money)
- //transfer the money
- D.money -= transaction_amount
- vendor_account.money += transaction_amount
+ //transfer the money
+ D.money -= transaction_amount
+ vendor_account.money += transaction_amount
- //create entries in the two account transaction logs
- var/datum/transaction/T = new()
- T.target_name = "[vendor_account.owner_name] (via [src.name])"
- T.purpose = "Purchase of [currently_vending.product_name]"
- if(transaction_amount > 0)
- T.amount = "([transaction_amount])"
- else
+ //create entries in the two account transaction logs
+ var/datum/transaction/T = new()
+ T.target_name = "[vendor_account.owner_name] (via [src.name])"
+ T.purpose = "Purchase of [currently_vending.product_name]"
+ if(transaction_amount > 0)
+ T.amount = "([transaction_amount])"
+ else
+ T.amount = "[transaction_amount]"
+ T.source_terminal = src.name
+ T.date = current_date_string
+ T.time = worldtime2text()
+ D.transaction_log.Add(T)
+ //
+ T = new()
+ T.target_name = D.owner_name
+ T.purpose = "Purchase of [currently_vending.product_name]"
T.amount = "[transaction_amount]"
- T.source_terminal = src.name
- T.date = current_date_string
- T.time = worldtime2text()
- D.transaction_log.Add(T)
- //
- T = new()
- T.target_name = D.owner_name
- T.purpose = "Purchase of [currently_vending.product_name]"
- T.amount = "[transaction_amount]"
- T.source_terminal = src.name
- T.date = current_date_string
- T.time = worldtime2text()
- vendor_account.transaction_log.Add(T)
+ T.source_terminal = src.name
+ T.date = current_date_string
+ T.time = worldtime2text()
+ vendor_account.transaction_log.Add(T)
- // Vend the item
- src.vend(src.currently_vending, usr)
- currently_vending = null
+ // Vend the item
+ src.vend(src.currently_vending, usr)
+ currently_vending = null
+ else
+ usr << "\icon[src]You don't have that much money!"
else
- usr << "\icon[src]You don't have that much money!"
+ usr << "\icon[src]Unable to access account. Check security settings and try again."
else
- usr << "\icon[src]Unable to access account. Check security settings and try again."
+ //Just Vend it.
+ src.vend(src.currently_vending, usr)
+ currently_vending = null
else
usr << "\icon[src]Unable to access vendor account. Please record the machine ID and call CentComm Support."
@@ -407,6 +422,13 @@
src.updateUsrDialog()
+/obj/machinery/vending/proc/stock(var/datum/data/vending_product/R, var/mob/user)
+ if(src.panel_open)
+ user << "\blue You stock the [src] with \a [R.product_name]"
+ R.amount++
+
+ src.updateUsrDialog()
+
/obj/machinery/vending/process()
if(stat & (BROKEN|NOPOWER))
return
@@ -589,11 +611,11 @@
/obj/item/weapon/reagent_containers/food/drinks/bottle/tequilla = 5,/obj/item/weapon/reagent_containers/food/drinks/bottle/vodka = 5,
/obj/item/weapon/reagent_containers/food/drinks/bottle/vermouth = 5,/obj/item/weapon/reagent_containers/food/drinks/bottle/rum = 5,
/obj/item/weapon/reagent_containers/food/drinks/bottle/wine = 5,/obj/item/weapon/reagent_containers/food/drinks/bottle/cognac = 5,
- /obj/item/weapon/reagent_containers/food/drinks/bottle/kahlua = 5,/obj/item/weapon/reagent_containers/food/drinks/beer = 6,
- /obj/item/weapon/reagent_containers/food/drinks/ale = 6,/obj/item/weapon/reagent_containers/food/drinks/bottle/orangejuice = 4,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/kahlua = 5,/obj/item/weapon/reagent_containers/food/drinks/cans/beer = 6,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/ale = 6,/obj/item/weapon/reagent_containers/food/drinks/bottle/orangejuice = 4,
/obj/item/weapon/reagent_containers/food/drinks/bottle/tomatojuice = 4,/obj/item/weapon/reagent_containers/food/drinks/bottle/limejuice = 4,
- /obj/item/weapon/reagent_containers/food/drinks/bottle/cream = 4,/obj/item/weapon/reagent_containers/food/drinks/tonic = 8,
- /obj/item/weapon/reagent_containers/food/drinks/cola = 8, /obj/item/weapon/reagent_containers/food/drinks/sodawater = 15,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/cream = 4,/obj/item/weapon/reagent_containers/food/drinks/cans/tonic = 8,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/cola = 8, /obj/item/weapon/reagent_containers/food/drinks/cans/sodawater = 15,
/obj/item/weapon/reagent_containers/food/drinks/drinkingglass = 30,/obj/item/weapon/reagent_containers/food/drinks/ice = 9,
/obj/item/weapon/reagent_containers/food/drinks/bottle/melonliquor = 2,/obj/item/weapon/reagent_containers/food/drinks/bottle/bluecuracao = 2,
/obj/item/weapon/reagent_containers/food/drinks/bottle/absinthe = 2,/obj/item/weapon/reagent_containers/food/drinks/bottle/grenadine = 5)
@@ -645,15 +667,15 @@
icon_state = "Cola_Machine"
product_slogans = "Robust Softdrinks: More robust than a toolbox to the head!"
product_ads = "Refreshing!;Hope you're thirsty!;Over 1 million drinks sold!;Thirsty? Why not cola?;Please, have a drink!;Drink up!;The best drinks in space."
- products = list(/obj/item/weapon/reagent_containers/food/drinks/cola = 10,/obj/item/weapon/reagent_containers/food/drinks/space_mountain_wind = 10,
- /obj/item/weapon/reagent_containers/food/drinks/dr_gibb = 10,/obj/item/weapon/reagent_containers/food/drinks/starkist = 10,
- /obj/item/weapon/reagent_containers/food/drinks/waterbottle = 10,/obj/item/weapon/reagent_containers/food/drinks/space_up = 10,
- /obj/item/weapon/reagent_containers/food/drinks/iced_tea = 10, /obj/item/weapon/reagent_containers/food/drinks/grape_juice = 10)
- contraband = list(/obj/item/weapon/reagent_containers/food/drinks/thirteenloko = 5)
- prices = list(/obj/item/weapon/reagent_containers/food/drinks/cola = 1,/obj/item/weapon/reagent_containers/food/drinks/space_mountain_wind = 1,
- /obj/item/weapon/reagent_containers/food/drinks/dr_gibb = 1,/obj/item/weapon/reagent_containers/food/drinks/starkist = 1,
- /obj/item/weapon/reagent_containers/food/drinks/waterbottle = 2,/obj/item/weapon/reagent_containers/food/drinks/space_up = 1,
- /obj/item/weapon/reagent_containers/food/drinks/iced_tea = 1,/obj/item/weapon/reagent_containers/food/drinks/grape_juice = 1)
+ products = list(/obj/item/weapon/reagent_containers/food/drinks/cans/cola = 10,/obj/item/weapon/reagent_containers/food/drinks/cans/space_mountain_wind = 10,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/dr_gibb = 10,/obj/item/weapon/reagent_containers/food/drinks/cans/starkist = 10,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle = 10,/obj/item/weapon/reagent_containers/food/drinks/cans/space_up = 10,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/iced_tea = 10, /obj/item/weapon/reagent_containers/food/drinks/cans/grape_juice = 10)
+ contraband = list(/obj/item/weapon/reagent_containers/food/drinks/cans/thirteenloko = 5)
+ prices = list(/obj/item/weapon/reagent_containers/food/drinks/cans/cola = 1,/obj/item/weapon/reagent_containers/food/drinks/cans/space_mountain_wind = 1,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/dr_gibb = 1,/obj/item/weapon/reagent_containers/food/drinks/cans/starkist = 1,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle = 2,/obj/item/weapon/reagent_containers/food/drinks/cans/space_up = 1,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/iced_tea = 1,/obj/item/weapon/reagent_containers/food/drinks/cans/grape_juice = 1)
//This one's from bay12
/obj/machinery/vending/cart
@@ -759,8 +781,8 @@
/obj/item/seeds/poppyseed = 3,/obj/item/seeds/ambrosiavulgarisseed = 3,/obj/item/seeds/whitebeetseed = 3,/obj/item/seeds/watermelonseed = 3,/obj/item/seeds/limeseed = 3,
/obj/item/seeds/lemonseed = 3,/obj/item/seeds/orangeseed = 3,/obj/item/seeds/grassseed = 3,/obj/item/seeds/cocoapodseed = 3,/obj/item/seeds/plumpmycelium = 2,
/obj/item/seeds/cabbageseed = 3,/obj/item/seeds/grapeseed = 3,/obj/item/seeds/pumpkinseed = 3,/obj/item/seeds/cherryseed = 3,/obj/item/seeds/plastiseed = 3,/obj/item/seeds/riceseed = 3)
- contraband = list(/obj/item/seeds/amanitamycelium = 2,/obj/item/seeds/glowshroom = 2,/obj/item/seeds/libertymycelium = 2,
- /obj/item/seeds/nettleseed = 2,/obj/item/seeds/reishimycelium = 2)
+ contraband = list(/obj/item/seeds/amanitamycelium = 2,/obj/item/seeds/glowshroom = 2,/obj/item/seeds/libertymycelium = 2,/obj/item/seeds/mtearseed = 2,
+ /obj/item/seeds/nettleseed = 2,/obj/item/seeds/reishimycelium = 2,/obj/item/seeds/reishimycelium = 2,/obj/item/seeds/shandseed = 2,)
premium = list(/obj/item/toy/waterflower = 1)
diff --git a/code/game/mecha/combat/marauder.dm b/code/game/mecha/combat/marauder.dm
index fdce02f5d2e..cdb3645c62d 100644
--- a/code/game/mecha/combat/marauder.dm
+++ b/code/game/mecha/combat/marauder.dm
@@ -14,7 +14,7 @@
var/smoke = 5
var/smoke_ready = 1
var/smoke_cooldown = 100
- var/datum/effect/effect/system/harmless_smoke_spread/smoke_system = new
+ var/datum/effect/effect/system/smoke_spread/smoke_system = new
operation_req_access = list(access_cent_specops)
wreckage = /obj/effect/decal/mecha_wreckage/marauder
add_req_access = 0
diff --git a/code/game/mecha/equipment/tools/tools.dm b/code/game/mecha/equipment/tools/tools.dm
index 73c7f5bd84f..416e2ff6cb9 100644
--- a/code/game/mecha/equipment/tools/tools.dm
+++ b/code/game/mecha/equipment/tools/tools.dm
@@ -94,7 +94,7 @@
else if(istype(target, /turf/simulated/mineral))
for(var/turf/simulated/mineral/M in range(chassis,1))
if(get_dir(chassis,M)&chassis.dir)
- M.gets_drilled()
+ M.GetDrilled()
log_message("Drilled through [target]")
if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment)
var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo
@@ -153,7 +153,7 @@
else if(istype(target, /turf/simulated/mineral))
for(var/turf/simulated/mineral/M in range(chassis,1))
if(get_dir(chassis,M)&chassis.dir)
- M.gets_drilled()
+ M.GetDrilled()
log_message("Drilled through [target]")
if(locate(/obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp) in chassis.equipment)
var/obj/structure/ore_box/ore_box = locate(/obj/structure/ore_box) in chassis:cargo
diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm
index 9e9e578ecf1..539ad4374e1 100644
--- a/code/game/mecha/mech_fabricator.dm
+++ b/code/game/mecha/mech_fabricator.dm
@@ -518,7 +518,7 @@
temp += "Return"
src.updateUsrDialog()
if(i || tech_output)
- src.visible_message("\icon[src] [src] beeps, \"Succesfully synchronized with R&D server. New data processed.\"")
+ src.visible_message("\icon[src] [src] beeps, \"Successfully synchronized with R&D server. New data processed.\"")
return
/obj/machinery/mecha_part_fabricator/proc/get_resource_cost_w_coeff(var/obj/item/part as obj,var/resource as text, var/roundto=1)
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index 65284a054d1..77807c2ca1c 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -237,7 +237,7 @@
target = safepick(view(3,target))
if(!target)
return
- if(get_dist(src, target)>1)
+ if(!target.Adjacent(src))
if(selected && selected.is_ranged())
selected.action(target)
else if(selected && selected.is_melee())
@@ -973,6 +973,11 @@
if (usr.stat || !ishuman(usr))
return
src.log_message("[usr] tries to move in.")
+ if(iscarbon(usr))
+ var/mob/living/carbon/C = usr
+ if(C.handcuffed)
+ usr << "\red Kinda hard to climb in while handcuffed don't you think?"
+ return
if (src.occupant)
usr << "\blue The [src.name] is already occupied!"
src.log_append_to_last("Permission denied.")
diff --git a/code/game/mecha/medical/odysseus.dm b/code/game/mecha/medical/odysseus.dm
index 008b5d819ab..5c188802e3e 100644
--- a/code/game/mecha/medical/odysseus.dm
+++ b/code/game/mecha/medical/odysseus.dm
@@ -108,6 +108,13 @@
holder.icon_state = "hudxeno"
else if(foundVirus)
holder.icon_state = "hudill"
+ else if(patient.has_brain_worms())
+ var/mob/living/simple_animal/borer/B = patient.has_brain_worms()
+ if(B.controlling)
+ holder.icon_state = "hudbrainworm"
+ else
+ holder.icon_state = "hudhealthy"
else
holder.icon_state = "hudhealthy"
+
C.images += holder
diff --git a/code/game/objects/effects/decals/Cleanable/aliens.dm b/code/game/objects/effects/decals/Cleanable/aliens.dm
index 7ee6aaa3b50..1df3acb2b73 100644
--- a/code/game/objects/effects/decals/Cleanable/aliens.dm
+++ b/code/game/objects/effects/decals/Cleanable/aliens.dm
@@ -1,63 +1,33 @@
-// Note: BYOND is object oriented. There is no reason for this to be copy/pasted blood code.
-
-/obj/effect/decal/cleanable/xenoblood
+/obj/effect/decal/cleanable/blood/xeno
name = "xeno blood"
desc = "It's green and acidic. It looks like... blood?"
- gender = PLURAL
- density = 0
- anchored = 1
- layer = 2
icon = 'icons/effects/blood.dmi'
- icon_state = "xfloor1"
- random_icon_states = list("xfloor1", "xfloor2", "xfloor3", "xfloor4", "xfloor5", "xfloor6", "xfloor7")
- var/list/viruses = list()
- blood_DNA = list()
+ basecolor = "#05EE05"
- Del()
- for(var/datum/disease/D in viruses)
- D.cure(0)
- ..()
-
-/obj/effect/decal/cleanable/xenoblood/xgibs/proc/streak(var/list/directions)
- spawn (0)
- var/direction = pick(directions)
- for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50; 4), i++)
- sleep(3)
- if (i > 0)
- var/obj/effect/decal/cleanable/xenoblood/b = new /obj/effect/decal/cleanable/xenoblood/xsplatter(src.loc)
- for(var/datum/disease/D in src.viruses)
- var/datum/disease/ND = D.Copy(1)
- b.viruses += ND
- ND.holder = b
- if (step_to(src, get_step(src, direction), 0))
- break
-
-/obj/effect/decal/cleanable/xenoblood/xsplatter
- random_icon_states = list("xgibbl1", "xgibbl2", "xgibbl3", "xgibbl4", "xgibbl5")
-
-/obj/effect/decal/cleanable/xenoblood/xgibs
+/obj/effect/decal/cleanable/blood/gibs/xeno
name = "xeno gibs"
desc = "Gnarly..."
- gender = PLURAL
- icon = 'icons/effects/blood.dmi'
icon_state = "xgib1"
random_icon_states = list("xgib1", "xgib2", "xgib3", "xgib4", "xgib5", "xgib6")
+ basecolor = "#05EE05"
-/obj/effect/decal/cleanable/xenoblood/xgibs/up
+/obj/effect/decal/cleanable/blood/gibs/xeno/update_icon()
+ color = "#FFFFFF"
+
+/obj/effect/decal/cleanable/blood/gibs/xeno/up
random_icon_states = list("xgib1", "xgib2", "xgib3", "xgib4", "xgib5", "xgib6","xgibup1","xgibup1","xgibup1")
-/obj/effect/decal/cleanable/xenoblood/xgibs/down
+/obj/effect/decal/cleanable/blood/gibs/xeno/down
random_icon_states = list("xgib1", "xgib2", "xgib3", "xgib4", "xgib5", "xgib6","xgibdown1","xgibdown1","xgibdown1")
-/obj/effect/decal/cleanable/xenoblood/xgibs/body
+/obj/effect/decal/cleanable/blood/gibs/xeno/body
random_icon_states = list("xgibhead", "xgibtorso")
-/obj/effect/decal/cleanable/xenoblood/xgibs/limb
+/obj/effect/decal/cleanable/blood/gibs/xeno/limb
random_icon_states = list("xgibleg", "xgibarm")
-/obj/effect/decal/cleanable/xenoblood/xgibs/core
+/obj/effect/decal/cleanable/blood/gibs/xeno/core
random_icon_states = list("xgibmid1", "xgibmid2", "xgibmid3")
/obj/effect/decal/cleanable/blood/xtracks
- icon_state = "xtracks"
- random_icon_states = null
\ No newline at end of file
+ basecolor = "#05EE05"
\ No newline at end of file
diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm
index 4f472f864ff..af0a3e65e1f 100644
--- a/code/game/objects/effects/decals/Cleanable/humans.dm
+++ b/code/game/objects/effects/decals/Cleanable/humans.dm
@@ -1,16 +1,21 @@
-#define DRYING_TIME 5 * 60*10 //for 1 unit of depth in puddle (amount var)
+#define DRYING_TIME 5 * 60*10 //for 1 unit of depth in puddle (amount var)
+
+var/global/list/image/splatter_cache=list()
+
/obj/effect/decal/cleanable/blood
name = "blood"
- desc = "It's red and gooey. Perhaps it's the chef's cooking?"
+ desc = "It's thick and gooey. Perhaps it's the chef's cooking?"
gender = PLURAL
density = 0
anchored = 1
layer = 2
icon = 'icons/effects/blood.dmi'
- icon_state = "floor1"
- random_icon_states = list("floor1", "floor2", "floor3", "floor4", "floor5", "floor6", "floor7")
+ icon_state = "mfloor1"
+ random_icon_states = list("mfloor1", "mfloor2", "mfloor3", "mfloor4", "mfloor5", "mfloor6", "mfloor7")
+ var/base_icon = 'icons/effects/blood.dmi'
var/list/viruses = list()
blood_DNA = list()
+ var/basecolor="#A10808" // Color when wet.
var/list/datum/disease2/disease/virus2 = list()
var/amount = 5
@@ -21,8 +26,11 @@
/obj/effect/decal/cleanable/blood/New()
..()
+ update_icon()
if(istype(src, /obj/effect/decal/cleanable/blood/gibs))
return
+ if(istype(src, /obj/effect/decal/cleanable/blood/tracks))
+ return // We handle our own drying.
if(src.type == /obj/effect/decal/cleanable/blood)
if(src.loc && isturf(src.loc))
for(var/obj/effect/decal/cleanable/blood/B in src.loc)
@@ -33,63 +41,92 @@
spawn(DRYING_TIME * (amount+1))
dry()
+/obj/effect/decal/cleanable/blood/update_icon()
+ if(basecolor == "rainbow") basecolor = "#[pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))]"
+ color = basecolor
+
/obj/effect/decal/cleanable/blood/HasEntered(mob/living/carbon/human/perp)
- if (!istype(perp))
- return
- if(amount < 1)
- return
+ if (!istype(perp))
+ return
+ if(amount < 1)
+ return
- if(perp.shoes)
- perp.shoes:track_blood = max(amount,perp.shoes:track_blood) //Adding blood to shoes
- if(!perp.shoes.blood_overlay)
- perp.shoes.generate_blood_overlay()
- if(!perp.shoes.blood_DNA)
- perp.shoes.blood_DNA = list()
- perp.shoes.overlays += perp.shoes.blood_overlay
- perp.update_inv_shoes(1)
- perp.shoes.blood_DNA |= blood_DNA.Copy()
- else
- perp.track_blood = max(amount,perp.track_blood) //Or feet
- if(!perp.feet_blood_DNA)
- perp.feet_blood_DNA = list()
- perp.feet_blood_DNA |= blood_DNA.Copy()
+ if(perp.shoes)
+ perp.shoes:track_blood = max(amount,perp.shoes:track_blood) //Adding blood to shoes
+ if(!perp.shoes.blood_overlay)
+ perp.shoes.generate_blood_overlay()
+ if(!perp.shoes.blood_DNA)
+ perp.shoes.blood_DNA = list()
+ perp.shoes.blood_overlay.color = basecolor
+ perp.shoes.overlays += perp.shoes.blood_overlay
+ perp.update_inv_shoes(1)
+ perp.shoes.blood_DNA |= blood_DNA.Copy()
+ perp.shoes.blood_color=basecolor
+ else
+ perp.track_blood = max(amount,perp.track_blood) //Or feet
+ if(!perp.feet_blood_DNA)
+ perp.feet_blood_DNA = list()
+ perp.feet_blood_DNA |= blood_DNA.Copy()
+ perp.feet_blood_color=basecolor
- amount--
+ amount--
/obj/effect/decal/cleanable/blood/proc/dry()
- name = "dried [src]"
- desc = "It's dark red and crusty. Someone is not doing their job."
- var/icon/I = icon(icon,icon_state)
- I.SetIntensity(0.7)
- icon = I
- amount = 0
+ name = "dried [src.name]"
+ desc = "It's dry and crusty. Someone is not doing their job."
+ color = adjust_brightness(color, -50)
+ amount = 0
+
+/obj/effect/decal/cleanable/blood/attack_hand(mob/living/carbon/human/user)
+ ..()
+ if (amount && istype(user))
+ add_fingerprint(user)
+ if (user.gloves)
+ return
+ var/taken = rand(1,amount)
+ amount -= taken
+ user << "You get some of \the [src] on your hands."
+ if (!user.blood_DNA)
+ user.blood_DNA = list()
+ user.blood_DNA |= blood_DNA.Copy()
+ user.bloody_hands += taken
+ user.hand_blood_color = basecolor
+ user.update_inv_gloves(1)
+ user.verbs += /mob/living/carbon/human/proc/bloody_doodle
/obj/effect/decal/cleanable/blood/splatter
- random_icon_states = list("gibbl1", "gibbl2", "gibbl3", "gibbl4", "gibbl5")
- amount = 2
-
-/obj/effect/decal/cleanable/blood/footprints
- name = "bloody footprints"
- desc = "Whoops..."
- icon='icons/effects/footprints.dmi'
- icon_state = "blood1"
- amount = 0
- random_icon_states = null
-
-/obj/effect/decal/cleanable/blood/tracks
- icon_state = "tracks"
- desc = "They look like tracks left by wheels."
- gender = PLURAL
- random_icon_states = null
- amount = 0
+ random_icon_states = list("mgibbl1", "mgibbl2", "mgibbl3", "mgibbl4", "mgibbl5")
+ amount = 2
/obj/effect/decal/cleanable/blood/drip
- name = "drips of blood"
- desc = "It's red."
- gender = PLURAL
- icon = 'icons/effects/drip.dmi'
- icon_state = "1"
+ name = "drips of blood"
+ desc = "It's red."
+ gender = PLURAL
+ icon = 'icons/effects/drip.dmi'
+ icon_state = "1"
+ random_icon_states = list("1","2","3","4","5")
+ amount = 0
+
+/obj/effect/decal/cleanable/blood/writing
+ icon_state = "tracks"
+ desc = "It looks like a writing in blood."
+ gender = NEUTER
+ random_icon_states = list("writing1","writing2","writing3","writing4","writing5")
amount = 0
+ var/message
+
+/obj/effect/decal/cleanable/blood/writing/New()
+ ..()
+ if(random_icon_states.len)
+ for(var/obj/effect/decal/cleanable/blood/writing/W in loc)
+ random_icon_states.Remove(W.icon_state)
+ icon_state = pick(random_icon_states)
+ else
+ icon_state = "writing1"
+
+/obj/effect/decal/cleanable/blood/writing/examine()
+ ..()
+ usr << "It reads: \"[message]\""
/obj/effect/decal/cleanable/blood/gibs
name = "gibs"
@@ -101,6 +138,22 @@
icon = 'icons/effects/blood.dmi'
icon_state = "gibbl5"
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6")
+ var/fleshcolor = "#FFFFFF"
+
+/obj/effect/decal/cleanable/blood/gibs/update_icon()
+
+ var/image/giblets = new(base_icon, "[icon_state]_flesh", dir)
+ if(!fleshcolor || fleshcolor == "rainbow")
+ fleshcolor = "#[pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))]"
+ giblets.color = fleshcolor
+
+ var/icon/blood = new(base_icon,"[icon_state]",dir)
+ if(basecolor == "rainbow") basecolor = "#[pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))]"
+ blood.Blend(basecolor,ICON_MULTIPLY)
+
+ icon = blood
+ overlays.Cut()
+ overlays += giblets
/obj/effect/decal/cleanable/blood/gibs/up
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibup1","gibup1","gibup1")
@@ -119,19 +172,21 @@
/obj/effect/decal/cleanable/blood/gibs/proc/streak(var/list/directions)
- spawn (0)
- var/direction = pick(directions)
- for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50; 4), i++)
- sleep(3)
- if (i > 0)
- var/obj/effect/decal/cleanable/blood/b = new /obj/effect/decal/cleanable/blood/splatter(src.loc)
- for(var/datum/disease/D in src.viruses)
- var/datum/disease/ND = D.Copy(1)
- b.viruses += ND
- ND.holder = b
+ spawn (0)
+ var/direction = pick(directions)
+ for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50; 4), i++)
+ sleep(3)
+ if (i > 0)
+ var/obj/effect/decal/cleanable/blood/b = new /obj/effect/decal/cleanable/blood/splatter(src.loc)
+ b.basecolor = src.basecolor
+ b.update_icon()
+ for(var/datum/disease/D in src.viruses)
+ var/datum/disease/ND = D.Copy(1)
+ b.viruses += ND
+ ND.holder = b
- if (step_to(src, get_step(src, direction), 0))
- break
+ if (step_to(src, get_step(src, direction), 0))
+ break
/obj/effect/decal/cleanable/mucus
@@ -144,4 +199,10 @@
icon = 'icons/effects/blood.dmi'
icon_state = "mucus"
random_icon_states = list("mucus")
+
var/list/datum/disease2/disease/virus2 = list()
+ var/dry=0 // Keeps the lag down
+
+/obj/effect/decal/cleanable/mucus/New()
+ spawn(DRYING_TIME * 2)
+ dry=1
diff --git a/code/game/objects/effects/decals/Cleanable/misc.dm b/code/game/objects/effects/decals/Cleanable/misc.dm
index 67c82a8f440..d52fd60b7eb 100644
--- a/code/game/objects/effects/decals/Cleanable/misc.dm
+++ b/code/game/objects/effects/decals/Cleanable/misc.dm
@@ -16,6 +16,13 @@
icon_state = "ash"
anchored = 1
+/obj/effect/decal/cleanable/ash/attack_hand(mob/user as mob)
+ user << "[src] sifts through your fingers."
+ var/turf/simulated/floor/F = get_turf(src)
+ if (istype(F))
+ F.dirt += 4
+ del(src)
+
/obj/effect/decal/cleanable/greenglow
New()
@@ -32,6 +39,7 @@
layer = 2
icon = 'icons/effects/effects.dmi'
icon_state = "dirt"
+ mouse_opacity = 0
/obj/effect/decal/cleanable/flour
name = "flour"
diff --git a/code/game/objects/effects/decals/Cleanable/robots.dm b/code/game/objects/effects/decals/Cleanable/robots.dm
index fa3aa3bfa9d..150197347de 100644
--- a/code/game/objects/effects/decals/Cleanable/robots.dm
+++ b/code/game/objects/effects/decals/Cleanable/robots.dm
@@ -1,25 +1,26 @@
-// Note: BYOND is object oriented. There is no reason for this to be copy/pasted blood code.
-
-/obj/effect/decal/cleanable/robot_debris
+/obj/effect/decal/cleanable/blood/gibs/robot
name = "robot debris"
desc = "It's a useless heap of junk... or is it?"
- gender = PLURAL
- density = 0
- anchored = 1
- layer = 2
icon = 'icons/mob/robots.dmi'
icon_state = "gib1"
+ basecolor="#030303"
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7")
-/obj/effect/decal/cleanable/robot_debris/proc/streak(var/list/directions)
+/obj/effect/decal/cleanable/blood/gibs/robot/update_icon()
+ color = "#FFFFFF"
+
+/obj/effect/decal/cleanable/blood/gibs/robot/dry() //pieces of robots do not dry up like
+ return
+
+/obj/effect/decal/cleanable/blood/gibs/robot/streak(var/list/directions)
spawn (0)
var/direction = pick(directions)
for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50; 4), i++)
sleep(3)
if (i > 0)
if (prob(40))
- /*var/obj/effect/decal/cleanable/oil/o =*/
- new /obj/effect/decal/cleanable/oil/streak(src.loc)
+ var/obj/effect/decal/cleanable/blood/oil/streak = new(src.loc)
+ streak.update_icon()
else if (prob(10))
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(3, 1, src)
@@ -27,31 +28,23 @@
if (step_to(src, get_step(src, direction), 0))
break
-/obj/effect/decal/cleanable/robot_debris/limb
+/obj/effect/decal/cleanable/blood/gibs/robot/limb
random_icon_states = list("gibarm", "gibleg")
-/obj/effect/decal/cleanable/robot_debris/up
+/obj/effect/decal/cleanable/blood/gibs/robot/up
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7","gibup1","gibup1") //2:7 is close enough to 1:4
-/obj/effect/decal/cleanable/robot_debris/down
+/obj/effect/decal/cleanable/blood/gibs/robot/down
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7","gibdown1","gibdown1") //2:7 is close enough to 1:4
-/obj/effect/decal/cleanable/oil
+/obj/effect/decal/cleanable/blood/oil
name = "motor oil"
desc = "It's black and greasy. Looks like Beepsky made another mess."
- gender = PLURAL
- density = 0
- anchored = 1
- layer = 2
- icon = 'icons/mob/robots.dmi'
- icon_state = "floor1"
- var/viruses = list()
- random_icon_states = list("floor1", "floor2", "floor3", "floor4", "floor5", "floor6", "floor7")
+ basecolor="#030303"
- Del()
- for(var/datum/disease/D in viruses)
- D.cure(0)
- ..()
+/obj/effect/decal/cleanable/blood/oil/dry()
+ return
-/obj/effect/decal/cleanable/oil/streak
- random_icon_states = list("streak1", "streak2", "streak3", "streak4", "streak5")
\ No newline at end of file
+/obj/effect/decal/cleanable/blood/oil/streak
+ random_icon_states = list("mgibbl1", "mgibbl2", "mgibbl3", "mgibbl4", "mgibbl5")
+ amount = 2
\ No newline at end of file
diff --git a/code/game/objects/effects/decals/Cleanable/tracks.dm b/code/game/objects/effects/decals/Cleanable/tracks.dm
new file mode 100644
index 00000000000..0382e3dbc99
--- /dev/null
+++ b/code/game/objects/effects/decals/Cleanable/tracks.dm
@@ -0,0 +1,161 @@
+// Stolen en masse from N3X15 of /vg/station with much gratitude.
+
+// The idea is to have 4 bits for coming and 4 for going.
+#define TRACKS_COMING_NORTH 1
+#define TRACKS_COMING_SOUTH 2
+#define TRACKS_COMING_EAST 4
+#define TRACKS_COMING_WEST 8
+#define TRACKS_GOING_NORTH 16
+#define TRACKS_GOING_SOUTH 32
+#define TRACKS_GOING_EAST 64
+#define TRACKS_GOING_WEST 128
+
+// 5 seconds
+#define TRACKS_CRUSTIFY_TIME 50
+
+// color-dir-dry
+var/global/list/image/fluidtrack_cache=list()
+
+/datum/fluidtrack
+ var/direction=0
+ var/basecolor="#A10808"
+ var/wet=0
+ var/fresh=1
+ var/crusty=0
+ var/image/overlay
+
+ New(_direction,_color,_wet)
+ src.direction=_direction
+ src.basecolor=_color
+ src.wet=_wet
+
+// Footprints, tire trails...
+/obj/effect/decal/cleanable/blood/tracks
+ amount = 0
+ random_icon_states = null
+ var/dirs=0
+ icon = 'icons/effects/fluidtracks.dmi'
+ icon_state = ""
+ var/coming_state="blood1"
+ var/going_state="blood2"
+ var/updatedtracks=0
+
+ // dir = id in stack
+ var/list/setdirs=list(
+ "1"=0,
+ "2"=0,
+ "4"=0,
+ "8"=0,
+ "16"=0,
+ "32"=0,
+ "64"=0,
+ "128"=0
+ )
+
+ // List of laid tracks and their colors.
+ var/list/datum/fluidtrack/stack=list()
+
+ /**
+ * Add tracks to an existing trail.
+ *
+ * @param DNA bloodDNA to add to collection.
+ * @param comingdir Direction tracks come from, or 0.
+ * @param goingdir Direction tracks are going to (or 0).
+ * @param bloodcolor Color of the blood when wet.
+ */
+ proc/AddTracks(var/list/DNA, var/comingdir, var/goingdir, var/bloodcolor="#A10808")
+ var/updated=0
+ // Shift our goingdir 4 spaces to the left so it's in the GOING bitblock.
+ var/realgoing=goingdir<<4
+
+ // Current bit
+ var/b=0
+
+ // When tracks will start to dry out
+ var/t=world.time + TRACKS_CRUSTIFY_TIME
+
+ var/datum/fluidtrack/track
+
+ // Process 4 bits
+ for(var/bi=0;bi<4;bi++)
+ b=1<>4
+
+ if(track.overlay)
+ track.overlay=null
+ var/image/I = image(icon, icon_state=state, dir=num2dir(truedir))
+ I.color = track.basecolor
+
+ track.fresh=0
+ track.overlay=I
+ stack[stack_idx]=track
+ overlays += I
+ updatedtracks=0 // Clear our memory of updated tracks.
+
+/obj/effect/decal/cleanable/blood/tracks/footprints
+ name = "wet footprints"
+ desc = "Whoops..."
+ coming_state = "human1"
+ going_state = "human2"
+ amount = 0
+
+/obj/effect/decal/cleanable/blood/tracks/wheels
+ name = "wet tracks"
+ desc = "Whoops..."
+ coming_state = "wheels"
+ going_state = ""
+ desc = "They look like tracks left by wheels."
+ gender = PLURAL
+ random_icon_states = null
+ amount = 0
\ No newline at end of file
diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm
index d1227d3aa38..63956f5e89a 100644
--- a/code/game/objects/effects/decals/cleanable.dm
+++ b/code/game/objects/effects/decals/cleanable.dm
@@ -1,7 +1,8 @@
/obj/effect/decal/cleanable
var/list/random_icon_states = list()
+ var/targeted_by = null // Used so cleanbots can't claim a mess.
/obj/effect/decal/cleanable/New()
if (random_icon_states && length(src.random_icon_states) > 0)
src.icon_state = pick(src.random_icon_states)
- ..()
\ No newline at end of file
+ ..()
diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm
index c0f783c52d6..8d2d69a654f 100644
--- a/code/game/objects/effects/effect_system.dm
+++ b/code/game/objects/effects/effect_system.dm
@@ -21,15 +21,6 @@ would spawn and follow the beaker, even if it is carried or thrown.
flags = TABLEPASS
mouse_opacity = 0
-/obj/effect/effect/smoke
- name = "smoke"
- icon = 'icons/effects/water.dmi'
- icon_state = "smoke"
- opacity = 1
- anchored = 0.0
- mouse_opacity = 0
- var/amount = 8.0
-
/obj/effect/proc/delete()
loc = null
if(reagents)
@@ -222,196 +213,186 @@ steam.start() -- spawns the effect
/////////////////////////////////////////////
-/obj/effect/effect/harmless_smoke
+/obj/effect/effect/smoke
name = "smoke"
icon_state = "smoke"
opacity = 1
anchored = 0.0
mouse_opacity = 0
var/amount = 6.0
+ var/time_to_live = 100
+
//Remove this bit to use the old smoke
icon = 'icons/effects/96x96.dmi'
pixel_x = -32
pixel_y = -32
-/obj/effect/effect/harmless_smoke/New()
+/obj/effect/effect/smoke/New()
..()
- spawn (100)
+ spawn (time_to_live)
delete()
return
-/obj/effect/effect/harmless_smoke/Move()
+/obj/effect/effect/smoke/HasEntered(mob/living/carbon/M as mob )
..()
- return
-
-/datum/effect/effect/system/harmless_smoke_spread
- var/total_smoke = 0 // To stop it being spammed and lagging!
- var/direction
-
- set_up(n = 5, c = 0, loca, direct)
- if(n > 10)
- n = 10
- number = n
- cardinals = c
- if(istype(loca, /turf/))
- location = loca
- else
- location = get_turf(loca)
- if(direct)
- direction = direct
-
-
- start()
- var/i = 0
- for(i=0, i 20)
- return
- spawn(0)
- if(holder)
- src.location = get_turf(holder)
- var/obj/effect/effect/harmless_smoke/smoke = new /obj/effect/effect/harmless_smoke(src.location)
- src.total_smoke++
- var/direction = src.direction
- if(!direction)
- if(src.cardinals)
- direction = pick(cardinal)
- else
- direction = pick(alldirs)
- for(i=0, i 20)
- n = 20
- number = n
- cardinals = c
- if(istype(loca, /turf/))
- location = loca
- else
- location = get_turf(loca)
- if(direct)
- direction = direct
+/datum/effect/effect/system/smoke_spread/set_up(n = 5, c = 0, loca, direct)
+ if(n > 10)
+ n = 10
+ number = n
+ cardinals = c
+ if(istype(loca, /turf/))
+ location = loca
+ else
+ location = get_turf(loca)
+ if(direct)
+ direction = direct
- start()
- var/i = 0
- for(i=0, i 20)
- return
- spawn(0)
- if(holder)
- src.location = get_turf(holder)
- var/obj/effect/effect/bad_smoke/smoke = new /obj/effect/effect/bad_smoke(src.location)
- src.total_smoke++
- var/direction = src.direction
- if(!direction)
- if(src.cardinals)
- direction = pick(cardinal)
- else
- direction = pick(alldirs)
- for(i=0, i 20)
+ return
+ spawn(0)
+ if(holder)
+ src.location = get_turf(holder)
+ var/obj/effect/effect/smoke/smoke = new smoke_type(src.location)
+ src.total_smoke++
+ var/direction = src.direction
+ if(!direction)
+ if(src.cardinals)
+ direction = pick(cardinal)
+ else
+ direction = pick(alldirs)
+ for(i=0, i 20)
- n = 20
- number = n
- cardinals = c
- if(istype(loca, /turf/))
- location = loca
- else
- location = get_turf(loca)
- if(direct)
- direction = direct
-
-
- start()
- var/i = 0
- for(i=0, i 20)
- return
- spawn(0)
- if(holder)
- src.location = get_turf(holder)
- var/obj/effect/effect/sleep_smoke/smoke = new /obj/effect/effect/sleep_smoke(src.location)
- src.total_smoke++
- var/direction = src.direction
- if(!direction)
- if(src.cardinals)
- direction = pick(cardinal)
- else
- direction = pick(alldirs)
- for(i=0, i 20)
- n = 20
- number = n
- cardinals = c
- if(istype(loca, /turf/))
- location = loca
- else
- location = get_turf(loca)
- if(direct)
- direction = direct
-
- start()
- var/i = 0
- for(i=0, i 20)
- return
- spawn(0)
- if(holder)
- src.location = get_turf(holder)
- var/obj/effect/effect/mustard_gas/smoke = new /obj/effect/effect/mustard_gas(src.location)
- src.total_smoke++
- var/direction = src.direction
- if(!direction)
- if(src.cardinals)
- direction = pick(cardinal)
- else
- direction = pick(alldirs)
- for(i=0, i 0)
for(var/datum/disease/D in viruses)
if(prob(virusProb))
diff --git a/code/game/objects/effects/spawners/gibspawner.dm b/code/game/objects/effects/spawners/gibspawner.dm
index c5194392374..5446ba348e6 100644
--- a/code/game/objects/effects/spawners/gibspawner.dm
+++ b/code/game/objects/effects/spawners/gibspawner.dm
@@ -17,7 +17,7 @@
..()
xeno
- gibtypes = list(/obj/effect/decal/cleanable/xenoblood/xgibs/up,/obj/effect/decal/cleanable/xenoblood/xgibs/down,/obj/effect/decal/cleanable/xenoblood/xgibs,/obj/effect/decal/cleanable/xenoblood/xgibs,/obj/effect/decal/cleanable/xenoblood/xgibs/body,/obj/effect/decal/cleanable/xenoblood/xgibs/limb,/obj/effect/decal/cleanable/xenoblood/xgibs/core)
+ gibtypes = list(/obj/effect/decal/cleanable/blood/gibs/xeno/up,/obj/effect/decal/cleanable/blood/gibs/xeno/down,/obj/effect/decal/cleanable/blood/gibs/xeno,/obj/effect/decal/cleanable/blood/gibs/xeno,/obj/effect/decal/cleanable/blood/gibs/xeno/body,/obj/effect/decal/cleanable/blood/gibs/xeno/limb,/obj/effect/decal/cleanable/blood/gibs/xeno/core)
gibamounts = list(1,1,1,1,1,1,1)
New()
@@ -27,7 +27,7 @@
robot
sparks = 1
- gibtypes = list(/obj/effect/decal/cleanable/robot_debris/up,/obj/effect/decal/cleanable/robot_debris/down,/obj/effect/decal/cleanable/robot_debris,/obj/effect/decal/cleanable/robot_debris,/obj/effect/decal/cleanable/robot_debris,/obj/effect/decal/cleanable/robot_debris/limb)
+ gibtypes = list(/obj/effect/decal/cleanable/blood/gibs/robot/up,/obj/effect/decal/cleanable/blood/gibs/robot/down,/obj/effect/decal/cleanable/blood/gibs/robot,/obj/effect/decal/cleanable/blood/gibs/robot,/obj/effect/decal/cleanable/blood/gibs/robot,/obj/effect/decal/cleanable/blood/gibs/robot/limb)
gibamounts = list(1,1,1,1,1,1)
New()
diff --git a/code/game/objects/explosion.dm b/code/game/objects/explosion.dm
index da4f51eef0a..5ba97f90053 100644
--- a/code/game/objects/explosion.dm
+++ b/code/game/objects/explosion.dm
@@ -7,6 +7,19 @@
else return dy + (0.5*dx)
+proc/trange(var/Dist=0,var/turf/Center=null)//alternative to range (ONLY processes turfs and thus less intensive)
+ if(Center==null) return
+
+ //var/x1=((Center.x-Dist)<1 ? 1 : Center.x-Dist)
+ //var/y1=((Center.y-Dist)<1 ? 1 : Center.y-Dist)
+ //var/x2=((Center.x+Dist)>world.maxx ? world.maxx : Center.x+Dist)
+ //var/y2=((Center.y+Dist)>world.maxy ? world.maxy : Center.y+Dist)
+
+ var/turf/x1y1 = locate(((Center.x-Dist)<1 ? 1 : Center.x-Dist),((Center.y-Dist)<1 ? 1 : Center.y-Dist),Center.z)
+ var/turf/x2y2 = locate(((Center.x+Dist)>world.maxx ? world.maxx : Center.x+Dist),((Center.y+Dist)>world.maxy ? world.maxy : Center.y+Dist),Center.z)
+ return block(x1y1,x2y2)
+
+
proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog = 1)
src = null //so we don't abort once src is deleted
spawn(0)
@@ -48,7 +61,7 @@ proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impa
var/y0 = epicenter.y
var/z0 = epicenter.z
- for(var/turf/T in range(epicenter, max(devastation_range, heavy_impact_range, light_impact_range)))
+ for(var/turf/T in trange(max(devastation_range, heavy_impact_range, light_impact_range), epicenter))
var/dist = cheap_pythag(T.x - x0,T.y - y0)
if(dist < devastation_range) dist = 1
@@ -85,4 +98,4 @@ proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impa
proc/secondaryexplosion(turf/epicenter, range)
for(var/turf/tile in range(range, epicenter))
- tile.ex_act(2)
+ tile.ex_act(2)
\ No newline at end of file
diff --git a/code/game/objects/explosion_recursive.dm b/code/game/objects/explosion_recursive.dm
index cfa1d7e0e53..9dc04ff6301 100644
--- a/code/game/objects/explosion_recursive.dm
+++ b/code/game/objects/explosion_recursive.dm
@@ -6,31 +6,12 @@
/obj
var/explosion_resistance
-/datum/explosion_turf
- var/turf/turf //The turf which will get ex_act called on it
- var/max_power //The largest amount of power the turf sustained
- New()
- ..()
- max_power = 0
- proc/save_power_if_larger(power)
- if(power > max_power)
- max_power = power
- return 1
- return 0
+var/list/explosion_turfs = list()
-var/list/datum/explosion_turf/explosion_turfs = list()
var/explosion_in_progress = 0
-proc/get_explosion_turf(var/turf/T)
- for( var/datum/explosion_turf/ET in explosion_turfs )
- if( T == ET.turf )
- return ET
- var/datum/explosion_turf/ET = new()
- ET.turf = T
- explosion_turfs += ET
- return ET
proc/explosion_rec(turf/epicenter, power)
@@ -52,9 +33,8 @@ proc/explosion_rec(turf/epicenter, power)
explosion_in_progress = 1
explosion_turfs = list()
- var/datum/explosion_turf/ETE = get_explosion_turf()
- ETE.turf = epicenter
- ETE.max_power = power
+
+ explosion_turfs[epicenter] = power
//This steap handles the gathering of turfs which will be ex_act() -ed in the next step. It also ensures each turf gets the maximum possible amount of power dealt to it.
for(var/direction in cardinal)
@@ -62,22 +42,21 @@ proc/explosion_rec(turf/epicenter, power)
T.explosion_spread(power - epicenter.explosion_resistance, direction)
//This step applies the ex_act effects for the explosion, as planned in the previous step.
- for( var/datum/explosion_turf/ET in explosion_turfs )
- if(ET.max_power <= 0) continue
- if(!ET.turf) continue
+ for(var/turf/T in explosion_turfs)
+ if(explosion_turfs[T] <= 0) continue
+ if(!T) continue
//Wow severity looks confusing to calculate... Fret not, I didn't leave you with any additional instructions or help. (just kidding, see the line under the calculation)
- var/severity = 4 - round(max(min( 3, ((ET.max_power - ET.turf.explosion_resistance) / (max(3,(power/3)))) ) ,1), 1)
- //sanity effective power on tile divided by either 3 or one third the total explosion power
+ var/severity = 4 - round(max(min( 3, ((explosion_turfs[T] - T.explosion_resistance) / (max(3,(power/3)))) ) ,1), 1) //sanity effective power on tile divided by either 3 or one third the total explosion power
// One third because there are three power levels and I
// want each one to take up a third of the crater
- var/x = ET.turf.x
- var/y = ET.turf.y
- var/z = ET.turf.z
- ET.turf.ex_act(severity)
- if(!ET.turf)
- ET.turf = locate(x,y,z)
- for( var/atom/A in ET.turf )
+ var/x = T.x
+ var/y = T.y
+ var/z = T.z
+ T.ex_act(severity)
+ if(!T)
+ T = locate(x,y,z)
+ for(var/atom/A in T)
A.ex_act(severity)
explosion_in_progress = 0
@@ -123,10 +102,9 @@ proc/explosion_rec(turf/epicenter, power)
new/obj/effect/debugging/marker(src)
*/
- var/datum/explosion_turf/ET = get_explosion_turf(src)
- if(ET.max_power >= power)
+ if(explosion_turfs[src] >= power)
return //The turf already sustained and spread a power greated than what we are dealing with. No point spreading again.
- ET.max_power = power
+ explosion_turfs[src] = power
var/spread_power = power - src.explosion_resistance //This is the amount of power that will be spread to the tile in the direction of the blast
var/side_spread_power = power - 2 * src.explosion_resistance //This is the amount of power that will be spread to the side tiles
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index dd445337b76..24e5479251c 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -1,7 +1,7 @@
/obj/item
name = "item"
icon = 'icons/obj/items.dmi'
- var/icon/blood_overlay = null //this saves our blood splatter overlay, which will be processed not to go over the edges of the sprite
+ var/image/blood_overlay = null //this saves our blood splatter overlay, which will be processed not to go over the edges of the sprite
var/abstract = 0
var/item_state = null
var/r_speed = 1.0
@@ -38,6 +38,7 @@
var/armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0)
var/list/allowed = null //suit storage stuff.
var/obj/item/device/uplink/hidden/hidden_uplink = null // All items can have an uplink hidden inside, just remember to add the triggers.
+ var/icon_override = null //Used to override hardcoded clothing dmis in human clothing proc.
/obj/item/device
icon = 'icons/obj/device.dmi'
@@ -315,6 +316,8 @@
return 0
if( (slot_flags & SLOT_TWOEARS) && H.r_ear )
return 0
+ if( w_class < 2 )
+ return 1
return 1
if(slot_r_ear)
if(H.r_ear)
@@ -323,6 +326,8 @@
return 0
if( (slot_flags & SLOT_TWOEARS) && H.l_ear )
return 0
+ if( w_class < 2 )
+ return 1
return 1
if(slot_w_uniform)
if(H.w_uniform)
@@ -348,7 +353,7 @@
H << "\red You need a jumpsuit before you can attach this [name]."
return 0
if(slot_flags & SLOT_DENYPOCKET)
- return
+ return 0
if( w_class <= 2 || (slot_flags & SLOT_POCKET) )
return 1
if(slot_r_store)
@@ -522,29 +527,28 @@
"\red You stab yourself in the eyes with [src]!" \
)
if(istype(M, /mob/living/carbon/human))
+ var/datum/organ/internal/eyes/eyes = H.internal_organs["eyes"]
+ eyes.damage += rand(3,4)
+ if(eyes.damage >= eyes.min_bruised_damage)
+ if(M.stat != 2)
+ if(eyes.robotic <= 1) //robot eyes bleeding might be a bit silly
+ M << "\red Your eyes start to bleed profusely!"
+ if(prob(50))
+ if(M.stat != 2)
+ M << "\red You drop what you're holding and clutch at your eyes!"
+ M.drop_item()
+ M.eye_blurry += 10
+ M.Paralyse(1)
+ M.Weaken(4)
+ if (eyes.damage >= eyes.min_broken_damage)
+ if(M.stat != 2)
+ M << "\red You go blind!"
var/datum/organ/external/affecting = M:get_organ("head")
if(affecting.take_damage(7))
M:UpdateDamageIcon()
else
M.take_organ_damage(7)
M.eye_blurry += rand(3,4)
- M.eye_stat += rand(2,4)
- if (M.eye_stat >= 10)
- M.eye_blurry += 15+(0.1*M.eye_blurry)
- M.disabilities |= NEARSIGHTED
- if(M.stat != 2)
- M << "\red Your eyes start to bleed profusely!"
- if(prob(50))
- if(M.stat != 2)
- M << "\red You drop what you're holding and clutch at your eyes!"
- M.drop_item()
- M.eye_blurry += 10
- M.Paralyse(1)
- M.Weaken(4)
- if (prob(M.eye_stat - 10 + 1))
- if(M.stat != 2)
- M << "\red You go blind!"
- M.sdisabilities |= BLIND
return
/obj/item/clean_blood()
@@ -569,6 +573,7 @@
//apply the blood-splatter overlay if it isn't already in there
if(!blood_DNA.len)
+ blood_overlay.color = blood_color
overlays += blood_overlay
//if this blood isn't already in the list, add it
@@ -589,4 +594,17 @@
//not sure if this is worth it. It attaches the blood_overlay to every item of the same type if they don't have one already made.
for(var/obj/item/A in world)
if(A.type == type && !A.blood_overlay)
- A.blood_overlay = I
\ No newline at end of file
+ A.blood_overlay = image(I)
+
+/obj/item/proc/showoff(mob/user)
+ for (var/mob/M in view(user))
+ M.show_message("[user] holds up [src]. Take a closer look.",1)
+
+/mob/living/carbon/verb/showoff()
+ set name = "Show Held Item"
+ set category = "Object"
+
+ var/obj/item/I = get_active_hand()
+ if(I && !I.abstract)
+ I.showoff(src)
+
diff --git a/code/game/objects/items/blueprints.dm b/code/game/objects/items/blueprints.dm
index 4e7ae4d6488..5c5b1b6fd81 100644
--- a/code/game/objects/items/blueprints.dm
+++ b/code/game/objects/items/blueprints.dm
@@ -1,6 +1,6 @@
/obj/item/blueprints
name = "station blueprints"
- desc = "Blueprints of the station. There's stamp \"Classified\" and several coffee stains on it."
+ desc = "Blueprints of the station. There is a \"Classified\" stamp and several coffee stains on it."
icon = 'icons/obj/items.dmi'
icon_state = "blueprints"
attack_verb = list("attacked", "bapped", "hit")
@@ -21,7 +21,7 @@
/obj/item/blueprints/attack_self(mob/M as mob)
if (!istype(M,/mob/living/carbon/human))
- M << "This is stack of useless pieces of harsh paper." //monkeys cannot into projecting
+ M << "This stack of blue paper means nothing to you." //monkeys cannot into projecting
return
interact()
return
@@ -53,18 +53,18 @@
switch (get_area_type())
if (AREA_SPACE)
text += {"
-
According this blueprints you are in open space now.
+
According the blueprints, you are now in outer space. Hold your breath.
"
- menu += "\[ Alert: None |"
- menu += " Red Alert |"
- menu += " Lockdown |"
- menu += " Biohazard \] "
-
- if (43) //Muskets' and Rockdtben's power monitor :D
- menu = "
Power Monitors - Please select one
"
- powmonitor = null
- powermonitors = list()
- var/powercount = 0
-
-
-
- for(var/obj/machinery/power/monitor/pMon in world)
- if(!(pMon.stat & (NOPOWER|BROKEN)) )
- powercount++
- powermonitors += pMon
-
-
- if(!powercount)
- menu += "\red No connection "
- else
-
- menu += ""
- var/count = 0
- for(var/obj/machinery/power/monitor/pMon in powermonitors)
- count++
- menu += " [pMon] "
-
- menu += ""
-
- if (433) //Muskets' and Rockdtben's power monitor :D
- menu = "
Power Monitor
"
- if(!powmonitor)
- menu += "\red No connection "
- else
- var/list/L = list()
- for(var/obj/machinery/power/terminal/term in powmonitor.powernet.nodes)
- if(istype(term.master, /obj/machinery/power/apc))
- var/obj/machinery/power/apc/A = term.master
- L += A
-
- menu += "
Total power: [powmonitor.powernet.avail] W Total load: [num2text(powmonitor.powernet.viewload,10)] W "
-
- menu += ""
-
- if(L.len > 0)
- menu += "Area Eqp./Lgt./Env. Load Cell"
-
- var/list/S = list(" Off","AOff"," On", " AOn")
- var/list/chg = list("N","C","F")
-
- for(var/obj/machinery/power/apc/A in L)
- menu += copytext(add_tspace(A.area.name, 30), 1, 30)
- menu += " [S[A.equipment+1]] [S[A.lighting+1]] [S[A.environ+1]] [add_lspace(A.lastused_total, 6)] [A.cell ? "[add_lspace(round(A.cell.percent()), 3)]% [chg[A.charging+1]]" : " N/C"] "
-
- menu += "
"
-
- if (44) //medical records //This thing only displays a single screen so it's hard to really get the sub-menu stuff working.
- menu = "
"
-
- menu += " Supply shuttle "
- menu += "Location: [supply_shuttle.moving ? "Moving to station ([supply_shuttle.eta] Mins.)":supply_shuttle.at_station ? "Station":"Dock"] "
- menu += "Current approved orders: "
- for(var/S in supply_shuttle.shoppinglist)
- var/datum/supply_order/SO = S
- menu += "
#[SO.ordernum] - [SO.object.name] approved by [SO.orderedby] [SO.comment ? "([SO.comment])":""]
"
- menu += ""
-
- menu += "Current requests: "
- for(var/S in supply_shuttle.requestlist)
- var/datum/supply_order/SO = S
- menu += "
#[SO.ordernum] - [SO.object.name] requested by [SO.orderedby]
"
- menu += "Upgrade NOW to Space Parts & Space Vendors PLUS for full remote order control and inventory management."
-
- if (48) //mulebot control
- var/obj/item/radio/integrated/mule/QC = radio
- if(!QC)
- menu = "Interlink Error - Please reinsert cartridge."
- return
-
- menu = "
M.U.L.E. bot Interlink V0.8
"
-
- if(!QC.active)
- // list of bots
- if(!QC.botlist || (QC.botlist && QC.botlist.len==0))
- menu += "No bots found. "
-
- else
- for(var/obj/machinery/bot/mulebot/B in QC.botlist)
- menu += "[B] at [get_area(B)] "
- menu += " Scan for active bots "
-
- else // bot selected, control it
-
- menu += "[QC.active] Status: (refresh) "
-
- if(!QC.botstatus)
- menu += "Waiting for response... "
- else
-
- menu += "Location: [QC.botstatus["loca"] ] "
- menu += "Mode: "
-
- switch(QC.botstatus["mode"])
- if(0)
- menu += "Ready"
- if(1)
- menu += "Loading/Unloading"
- if(2)
- menu += "Navigating to Delivery Location"
- if(3)
- menu += "Navigating to Home"
- if(4)
- menu += "Waiting for clear path"
- if(5,6)
- menu += "Calculating navigation path"
- if(7)
- menu += "Unable to locate destination"
- var/obj/structure/closet/crate/C = QC.botstatus["load"]
- menu += " Current Load: [ !C ? "none" : "[C.name] (unload)" ] "
- menu += "Destination: [!QC.botstatus["dest"] ? "none" : QC.botstatus["dest"] ] (set) "
- menu += "Power: [QC.botstatus["powr"]]% "
- menu += "Home: [!QC.botstatus["home"] ? "none" : QC.botstatus["home"] ] "
- menu += "Auto Return Home: [QC.botstatus["retn"] ? "OnOff" : "(On) Off"] "
- menu += "Auto Pickup Crate: [QC.botstatus["pick"] ? "OnOff" : "(On) Off"]