Merge branch 'master' into upstream-merge-37476

# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
This commit is contained in:
LetterJay
2018-05-20 23:11:16 -05:00
242 changed files with 3178 additions and 2201 deletions
+1 -1
View File
@@ -95,7 +95,7 @@
SSblackbox.record_feedback("tally", "admin_verb", 1, "Jump To Key") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/Getmob(mob/M in GLOB.mob_list)
/client/proc/Getmob(mob/M in GLOB.mob_list - GLOB.dummy_mob_list)
set category = "Admin"
set name = "Get Mob"
set desc = "Mob to teleport"
+1 -1
View File
@@ -27,7 +27,7 @@
if(isnewplayer(M))
continue
if (M.stat == DEAD || (M.client && M.client.holder && (M.client.prefs.chat_toggles & CHAT_DEAD))) //admins can toggle deadchat on and off. This is a proc in admin.dm and is only give to Administrators and above
M.show_message(rendered, 2)
to_chat(M, rendered)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Dsay") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -151,6 +151,7 @@
desc = "You get the feeling that you shouldn't be standing here."
clockwork_desc = "A sigil that will soon erupt and smite any unenlightened nearby."
icon = 'icons/effects/96x96.dmi'
icon_state = ""
pixel_x = -32
pixel_y = -32
layer = BELOW_MOB_LAYER
+2 -4
View File
@@ -33,10 +33,8 @@
desc = "A sword humming with unholy energy. It glows with a dim red light."
icon_state = "cultblade"
item_state = "cultblade"
lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi'
righthand_file = 'icons/mob/inhands/64x64_righthand.dmi'
inhand_x_dimension = 64
inhand_y_dimension = 64
lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
flags_1 = CONDUCT_1
sharpness = IS_SHARP
w_class = WEIGHT_CLASS_BULKY
+5
View File
@@ -708,6 +708,11 @@ structure_check() searches for nearby cultist structures required for the invoca
fail_invoke()
log_game("Summon Cultist rune failed - target died")
return
if(cultist_to_summon.pulledby || cultist_to_summon.buckled)
to_chat(user, "<span class='cult italic'>[cultist_to_summon] is being held in place!</span>")
fail_invoke()
log_game("Summon Cultist rune failed - target restrained")
return
if(!iscultist(cultist_to_summon))
to_chat(user, "<span class='cult italic'>[cultist_to_summon] is not a follower of the Geometer!</span>")
fail_invoke()
+1 -1
View File
@@ -190,7 +190,7 @@
return ..()
/mob/living/simple_animal/hostile/morph/AttackingTarget()
if(!melee_damage_disguised)
if(morphed && !melee_damage_disguised)
to_chat(src, "<span class='warning'>You can not attack while disguised!</span>")
return
if(isliving(target)) //Eat Corpses to regen health
@@ -501,16 +501,37 @@ This is here to make the tiles around the station mininuke change when it's arme
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 30, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
var/fake = FALSE
var/turf/lastlocation
var/last_disk_move
/obj/item/disk/nuclear/Initialize()
. = ..()
if(!fake)
GLOB.poi_list |= src
last_disk_move = world.time
START_PROCESSING(SSobj, src)
/obj/item/disk/nuclear/ComponentInitialize()
. = ..()
AddComponent(/datum/component/stationloving, !fake)
/obj/item/disk/nuclear/process()
if(fake)
STOP_PROCESSING(SSobj, src)
CRASH("A fake nuke disk tried to call process(). Who the fuck and how the fuck")
var/turf/newturf = get_turf(src)
if(newturf && lastlocation == newturf)
if(last_disk_move < world.time - 5000 && prob((world.time - 5000 - last_disk_move)*0.00001))
var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control
if(istype(loneop))
loneop.weight += 1
else
lastlocation = newturf
last_disk_move = world.time
var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control
if(istype(loneop) && prob(loneop.weight))
loneop.weight = max(loneop.weight - 1, 0)
/obj/item/disk/nuclear/examine(mob/user)
. = ..()
if(!fake)
@@ -66,7 +66,7 @@
name = "pile of viscera"
desc = "A repulsive pile of guts and gore."
gender = NEUTER
random_icon_states = list("innards")
icon_state = "innards"
/mob/living/simple_animal/slaughter/phasein()
. = ..()
+4 -4
View File
@@ -493,10 +493,10 @@
D.pixel_z = target.pixel_z
if(do_mob(src, target, 100))
to_chat(src, "<span class='info'>Dismantling complete.</span>")
var/obj/item/stack/sheet/metal/M = new /obj/item/stack/sheet/metal(target.loc)
M.amount = 5
var/atom/Tsec = target.drop_location()
new /obj/item/stack/sheet/metal(Tsec, 5)
for(var/obj/item/I in target.component_parts)
I.forceMove(M.drop_location())
I.forceMove(Tsec)
var/obj/effect/temp_visual/swarmer/disintegration/N = new /obj/effect/temp_visual/swarmer/disintegration(get_turf(target))
N.pixel_x = target.pixel_x
N.pixel_y = target.pixel_y
@@ -505,7 +505,7 @@
if(istype(target, /obj/machinery/computer))
var/obj/machinery/computer/C = target
if(C.circuit)
C.circuit.forceMove(M.drop_location())
C.circuit.forceMove(Tsec)
qdel(target)
+23 -18
View File
@@ -3,6 +3,7 @@
#define WIRE_PULSE_SPECIAL (1<<2)
#define WIRE_RADIO_RECEIVE (1<<3)
#define WIRE_RADIO_PULSE (1<<4)
#define ASSEMBLY_BEEP_VOLUME 5
/obj/item/assembly
name = "assembly"
@@ -16,6 +17,8 @@
throw_speed = 3
throw_range = 7
var/is_position_sensitive = FALSE //set to true if the device has different icons for each position.
//This will prevent things such as visible lasers from facing the incorrect direction when transformed by assembly_holder's update_icon()
var/secured = TRUE
var/list/attached_overlays = null
var/obj/item/assembly_holder/holder = null
@@ -30,14 +33,18 @@
/obj/item/assembly/proc/on_attach()
/obj/item/assembly/proc/on_detach()
/obj/item/assembly/proc/on_detach() //call this when detaching it from a device. handles any special functions that need to be updated ex post facto
if(!holder)
return FALSE
forceMove(holder.drop_location())
holder = null
return TRUE
/obj/item/assembly/proc/holder_movement() //Called when the holder is moved
return
/obj/item/assembly/proc/describe() // Called by grenades to describe the state of the trigger (time left, etc)
return "The trigger assembly looks broken!"
if(!holder)
return FALSE
setDir(holder.dir)
return TRUE
/obj/item/assembly/proc/is_secured(mob/user)
if(!secured)
@@ -47,7 +54,7 @@
//Called when another assembly acts on this one, var/radio will determine where it came from for wire calcs
/obj/item/assembly/proc/pulsed(radio = 0)
/obj/item/assembly/proc/pulsed(radio = FALSE)
if(wire_type & WIRE_RECEIVE)
INVOKE_ASYNC(src, .proc/activate)
if(radio && (wire_type & WIRE_RADIO_RECEIVE))
@@ -56,7 +63,7 @@
//Called when this device attempts to act on another device, var/radio determines if it was sent via radio or direct
/obj/item/assembly/proc/pulse(radio = 0)
/obj/item/assembly/proc/pulse(radio = FALSE)
if(connected && wire_type)
connected.pulse_assembly(src)
return TRUE
@@ -91,21 +98,19 @@
else
to_chat(user, "<span class='warning'>Both devices must be in attachable mode to be attached together.</span>")
return
if(istype(W, /obj/item/screwdriver))
if(toggle_secure())
to_chat(user, "<span class='notice'>\The [src] is ready!</span>")
else
to_chat(user, "<span class='notice'>\The [src] can now be attached!</span>")
return
..()
/obj/item/assembly/screwdriver_act(mob/living/user, obj/item/I)
if(toggle_secure())
to_chat(user, "<span class='notice'>\The [src] is ready!</span>")
else
to_chat(user, "<span class='notice'>\The [src] can now be attached!</span>")
add_fingerprint(user)
return TRUE
/obj/item/assembly/examine(mob/user)
..()
if(secured)
to_chat(user, "\The [src] is secured and ready to be used.")
else
to_chat(user, "\The [src] can be attached to other things.")
to_chat(user, "<span class='notice'>\The [src] [secured? "is secured and ready to be used!" : "can be attached to other things."]</span>")
/obj/item/assembly/attack_self(mob/user)
+51 -16
View File
@@ -13,11 +13,14 @@
var/obj/item/assembly_holder/bombassembly = null //The first part of the bomb is an assembly holder, holding an igniter+some device
var/obj/item/tank/bombtank = null //the second part of the bomb is a plasma tank
/obj/item/onetankbomb/IsSpecialAssembly()
return TRUE
/obj/item/onetankbomb/examine(mob/user)
bombtank.examine(user)
/obj/item/onetankbomb/update_icon()
cut_overlays()
if(bombtank)
icon = bombtank.icon
icon_state = bombtank.icon_state
@@ -30,29 +33,37 @@
if(istype(W, /obj/item/analyzer))
bombtank.attackby(W, user)
return
if(istype(W, /obj/item/wrench) && !status) //This is basically bomb assembly code inverted. apparently it works.
to_chat(user, "<span class='notice'>You disassemble [src].</span>")
add_fingerprint(user)
..()
/obj/item/onetankbomb/wrench_act(mob/living/user, obj/item/I)
to_chat(user, "<span class='notice'>You disassemble [src]!</span>")
if(bombassembly)
bombassembly.forceMove(drop_location())
bombassembly.master = null
bombassembly = null
if(bombtank)
bombtank.forceMove(drop_location())
bombtank.master = null
bombtank = null
qdel(src)
return TRUE
qdel(src)
/obj/item/onetankbomb/welder_act(mob/living/user, obj/item/I)
. = FALSE
if(status)
to_chat(user, "<span class='notice'>[bombtank] already has a pressure hole!</span>")
return
var/obj/item/weldingtool/WT = W
if((istype(WT) && WT.welding))
if(!status)
status = TRUE
GLOB.bombers += "[key_name(user)] welded a single tank bomb. Temp: [bombtank.air_contents.temperature-T0C]"
message_admins("[key_name_admin(user)] welded a single tank bomb. Temp: [bombtank.air_contents.temperature-T0C]")
to_chat(user, "<span class='notice'>A pressure hole has been bored to [bombtank] valve. \The [bombtank] can now be ignited.</span>")
add_fingerprint(user)
..()
if(!I.tool_start_check(user, amount=0))
return
if(I.use_tool(src, user, 0, volume=40))
status = TRUE
GLOB.bombers += "[key_name(user)] welded a single tank bomb. Temp: [bombtank.air_contents.temperature-T0C]"
message_admins("[key_name_admin(user)] welded a single tank bomb. Temp: [bombtank.air_contents.temperature-T0C]")
to_chat(user, "<span class='notice'>A pressure hole has been bored to [bombtank] valve. \The [bombtank] can now be ignited.</span>")
add_fingerprint(user)
return TRUE
/obj/item/onetankbomb/attack_self(mob/user) //pressing the bomb accesses its assembly
bombassembly.attack_self(user, TRUE)
@@ -60,16 +71,20 @@
return
/obj/item/onetankbomb/receive_signal() //This is mainly called by the sensor through sense() to the holder, and from the holder to here.
visible_message("[icon2html(src, viewers(src))] *beep* *beep*", "*beep* *beep*")
audible_message("[icon2html(src, hearers(src))] *beep* *beep* *beep*")
playsound(src, 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE)
sleep(10)
if(!src)
if(QDELETED(src))
return
if(status)
bombtank.ignite() //if its not a dud, boom (or not boom if you made shitty mix) the ignite proc is below, in this file
else
bombtank.release()
//Assembly / attached device memes
/obj/item/onetankbomb/Crossed(atom/movable/AM as mob|obj) //for mousetraps
. = ..()
if(bombassembly)
bombassembly.Crossed(AM)
@@ -77,6 +92,26 @@
if(bombassembly)
bombassembly.on_found(finder)
/obj/item/onetankbomb/attack_hand() //also for mousetraps
. = ..()
if(.)
return
if(bombassembly)
bombassembly.attack_hand()
/obj/item/onetankbomb/Move()
. = ..()
if(bombassembly)
bombassembly.setDir(dir)
bombassembly.Move()
/obj/item/onetankbomb/dropped()
. = ..()
if(bombassembly)
bombassembly.dropped()
// ---------- Procs below are for tanks that are used exclusively in 1-tank bombs ----------
+14 -21
View File
@@ -2,10 +2,10 @@
name = "blast door controller"
desc = "A small electronic device able to control a blast door remotely."
icon_state = "control"
attachable = 1
attachable = TRUE
var/id = null
var/can_change_id = 0
var/cooldown = 0//Door cooldowns
var/cooldown = FALSE //Door cooldowns
/obj/item/assembly/control/examine(mob/user)
..()
@@ -13,15 +13,14 @@
to_chat(user, "<span class='notice'>Its channel ID is '[id]'.</span>")
/obj/item/assembly/control/activate()
cooldown = 1
cooldown = TRUE
var/openclose
for(var/obj/machinery/door/poddoor/M in GLOB.machines)
if(M.id == src.id)
if(openclose == null)
openclose = M.density
INVOKE_ASYNC(M, openclose ? /obj/machinery/door/poddoor.proc/open : /obj/machinery/door/poddoor.proc/close)
sleep(10)
cooldown = 0
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 10)
/obj/item/assembly/control/airlock
@@ -38,7 +37,7 @@
*/
/obj/item/assembly/control/airlock/activate()
cooldown = 1
cooldown = TRUE
var/doors_need_closing = FALSE
var/list/obj/machinery/door/airlock/open_or_close = list()
for(var/obj/machinery/door/airlock/D in GLOB.airlocks)
@@ -66,8 +65,7 @@
for(var/D in open_or_close)
INVOKE_ASYNC(D, doors_need_closing ? /obj/machinery/door/airlock.proc/close : /obj/machinery/door/airlock.proc/open)
sleep(10)
cooldown = 0
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 10)
/obj/item/assembly/control/massdriver
@@ -75,7 +73,7 @@
desc = "A small electronic device able to control a mass driver."
/obj/item/assembly/control/massdriver/activate()
cooldown = 1
cooldown = TRUE
for(var/obj/machinery/door/poddoor/M in GLOB.machines)
if (M.id == src.id)
INVOKE_ASYNC(M, /obj/machinery/door/poddoor.proc/open)
@@ -92,8 +90,7 @@
if (M.id == src.id)
INVOKE_ASYNC(M, /obj/machinery/door/poddoor.proc/close)
sleep(10)
cooldown = 0
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 10)
/obj/item/assembly/control/igniter
@@ -101,7 +98,7 @@
desc = "A remote controller for a mounted igniter."
/obj/item/assembly/control/igniter/activate()
cooldown = 1
cooldown = TRUE
for(var/obj/machinery/sparker/M in GLOB.machines)
if (M.id == src.id)
INVOKE_ASYNC(M, /obj/machinery/sparker.proc/ignite)
@@ -112,22 +109,19 @@
M.on = !M.on
M.icon_state = "igniter[M.on]"
sleep(30)
cooldown = 0
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 30)
/obj/item/assembly/control/flasher
name = "flasher controller"
desc = "A remote controller for a mounted flasher."
/obj/item/assembly/control/flasher/activate()
cooldown = 1
cooldown = TRUE
for(var/obj/machinery/flasher/M in GLOB.machines)
if(M.id == src.id)
INVOKE_ASYNC(M, /obj/machinery/flasher.proc/flash)
sleep(50)
cooldown = 0
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 50)
/obj/item/assembly/control/crematorium
@@ -135,10 +129,9 @@
desc = "An evil-looking remote controller for a crematorium."
/obj/item/assembly/control/crematorium/activate()
cooldown = 1
cooldown = TRUE
for (var/obj/structure/bodycontainer/crematorium/C in GLOB.crematoriums)
if (C.id == id)
C.cremate(usr)
sleep(50)
cooldown = 0
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 50)
+5 -3
View File
@@ -93,7 +93,7 @@
if(crit_fail || (world.time < last_trigger + cooldown))
return FALSE
last_trigger = world.time
playsound(src, 'sound/weapons/flash.ogg', 100, 1)
playsound(src, 'sound/weapons/flash.ogg', 100, TRUE)
times_used++
flash_recharge()
update_icon(TRUE)
@@ -195,6 +195,8 @@
/obj/item/assembly/flash/cyborg/attackby(obj/item/W, mob/user, params)
return
/obj/item/assembly/flash/cyborg/screwdriver_act(mob/living/user, obj/item/I)
return
/obj/item/assembly/flash/memorizer
name = "memorizer"
@@ -226,7 +228,7 @@
return FALSE
overheat = TRUE
addtimer(CALLBACK(src, .proc/cooldown), flashcd)
playsound(src, 'sound/weapons/flash.ogg', 100, 1)
playsound(src, 'sound/weapons/flash.ogg', 100, TRUE)
update_icon(1)
return TRUE
@@ -272,7 +274,7 @@
return
crit_fail = FALSE
times_used = 0
playsound(src, 'sound/items/deconstruct.ogg', 50, 1)
playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE)
update_icon()
flash.crit_fail = TRUE
flash.update_icon()
+18 -19
View File
@@ -3,10 +3,10 @@
desc = "Used for scanning and monitoring health."
icon_state = "health"
materials = list(MAT_METAL=800, MAT_GLASS=200)
attachable = 1
secured = 0
attachable = TRUE
secured = FALSE
var/scanning = 0
var/scanning = FALSE
var/health_scan
var/alarm_health = 0
@@ -16,31 +16,28 @@
/obj/item/assembly/health/activate()
if(!..())
return 0//Cooldown check
return FALSE//Cooldown check
toggle_scan()
return 0
return TRUE
/obj/item/assembly/health/toggle_secure()
secured = !secured
if(secured && scanning)
START_PROCESSING(SSobj, src)
else
scanning = 0
scanning = FALSE
STOP_PROCESSING(SSobj, src)
update_icon()
return secured
/obj/item/assembly/health/attackby(obj/item/W as obj, mob/user as mob)
if(istype(W, /obj/item/multitool))
if(alarm_health == 0)
alarm_health = -90
user.show_message("You toggle [src] to \"detect death\" mode.")
else
alarm_health = 0
user.show_message("You toggle [src] to \"detect critical state\" mode.")
return
/obj/item/assembly/health/multitool_act(mob/living/user, obj/item/I)
if(alarm_health == 0)
alarm_health = -90
to_chat(user, "<span class='notice'>You toggle [src] to \"detect death\" mode.</span>")
else
return ..()
alarm_health = 0
to_chat(user, "<span class='notice'>You toggle [src] to \"detect critical state\" mode.</span>")
return TRUE
/obj/item/assembly/health/process()
if(!scanning || !secured)
@@ -58,7 +55,8 @@
health_scan = M.health
if(health_scan <= alarm_health)
pulse()
audible_message("[icon2html(src, hearers(src))] *beep* *beep*", "*beep* *beep*")
audible_message("[icon2html(src, hearers(src))] *beep* *beep* *beep*")
playsound(src, 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE)
toggle_scan()
return
return
@@ -77,8 +75,9 @@
. = ..()
if(!secured)
user.show_message("<span class='warning'>The [name] is unsecured!</span>")
return 0
var/dat = "<TT><B>Health Sensor</B> <A href='?src=[REF(src)];scanning=1'>[scanning?"On":"Off"]</A>"
return FALSE
var/dat = "<TT><B>Health Sensor</B></TT>"
dat += "<BR><A href='?src=[REF(src)];scanning=1'>[scanning?"On":"Off"]</A>"
if(scanning && health_scan)
dat += "<BR>Health: [health_scan]"
user << browse(dat, "window=hscan")
+16 -16
View File
@@ -1,16 +1,16 @@
// See _DEFINES/is_helpers.dm for type helpers
/*
Name: IsSpecialAssembly
Desc: If true is an object that can be attached to an assembly holder but is a special thing like a plasma can or door
*/
/obj/proc/IsSpecialAssembly()
return 0
/*
Name: IsAssemblyHolder
Desc: If true is an object that can hold an assemblyholder object
*/
/obj/proc/IsAssemblyHolder()
return 0
// See _DEFINES/is_helpers.dm for type helpers
/*
Name: IsSpecialAssembly
Desc: If true is an object that can be attached to an assembly holder but is a special thing like a plasma can or door
*/
/obj/proc/IsSpecialAssembly()
return FALSE
/*
Name: IsAssemblyHolder
Desc: If true is an object that can hold an assemblyholder object
*/
/obj/proc/IsAssemblyHolder()
return FALSE
+39 -28
View File
@@ -15,7 +15,7 @@
var/obj/item/assembly/a_right = null
/obj/item/assembly_holder/IsAssemblyHolder()
return 1
return TRUE
/obj/item/assembly_holder/proc/assemble(obj/item/assembly/A, obj/item/assembly/A2, mob/user)
@@ -37,6 +37,7 @@
a_left = A
else
a_right = A
A.holder_movement()
/obj/item/assembly_holder/update_icon()
cut_overlays()
@@ -46,11 +47,16 @@
add_overlay("[O]_l")
if(a_right)
var/mutable_appearance/right = mutable_appearance(icon, "[a_right.icon_state]_left")
right.transform = matrix(-1, 0, 0, 0, 1, 0)
for(var/O in a_right.attached_overlays)
right.add_overlay("[O]_l")
add_overlay(right)
if(a_right.is_position_sensitive)
add_overlay("[a_right.icon_state]_right")
for(var/O in a_right.attached_overlays)
add_overlay("[O]_r")
else
var/mutable_appearance/right = mutable_appearance(icon, "[a_right.icon_state]_left")
right.transform = matrix(-1, 0, 0, 0, 1, 0)
for(var/O in a_right.attached_overlays)
right.add_overlay("[O]_l")
add_overlay(right)
if(master)
master.update_icon()
@@ -69,32 +75,37 @@
/obj/item/assembly_holder/Move()
. = ..()
if(a_left && a_right)
if(a_left)
a_left.holder_movement()
if(a_right)
a_right.holder_movement()
/obj/item/assembly_holder/dropped(mob/user)
. = ..()
if(a_left)
a_left.dropped()
if(a_right)
a_right.dropped()
/obj/item/assembly_holder/attack_hand()//Perhapse this should be a holder_pickup proc instead, can add if needbe I guess
. = ..()
if(.)
return
if(a_left && a_right)
a_left.holder_movement()
a_right.holder_movement()
if(a_left)
a_left.attack_hand()
if(a_right)
a_right.attack_hand()
/obj/item/assembly_holder/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/screwdriver))
var/turf/T = get_turf(src)
if(!T)
return 0
if(a_left)
a_left.holder = null
a_left.forceMove(T)
if(a_right)
a_right.holder = null
a_right.forceMove(T)
qdel(src)
else
..()
/obj/item/assembly_holder/screwdriver_act(mob/user, obj/item/tool)
to_chat(user, "<span class='notice'>You disassemble [src]!</span>")
if(a_left)
a_left.on_detach()
a_left = null
if(a_right)
a_right.on_detach()
a_right = null
qdel(src)
return TRUE
/obj/item/assembly_holder/attack_self(mob/user)
src.add_fingerprint(user)
@@ -115,12 +126,12 @@
/obj/item/assembly_holder/proc/process_activation(obj/D, normal = 1, special = 1)
if(!D)
return 0
return FALSE
if((normal) && (a_right) && (a_left))
if(a_right != D)
a_right.pulsed(0)
a_right.pulsed(FALSE)
if(a_left != D)
a_left.pulsed(0)
a_left.pulsed(FALSE)
if(master)
master.receive_signal()
return 1
return TRUE
+2 -2
View File
@@ -23,12 +23,12 @@
/obj/item/assembly/igniter/activate()
if(!..())
return 0//Cooldown check
return FALSE//Cooldown check
var/turf/location = get_turf(loc)
if(location)
location.hotspot_expose(1000,1000)
sparks.start()
return 1
return TRUE
/obj/item/assembly/igniter/attack_self(mob/user)
activate()
+49 -16
View File
@@ -3,6 +3,7 @@
desc = "Emits a visible or invisible beam and is triggered when the beam is interrupted."
icon_state = "infrared"
materials = list(MAT_METAL=1000, MAT_GLASS=500)
is_position_sensitive = TRUE
var/on = FALSE
var/visible = FALSE
@@ -10,6 +11,7 @@
var/list/obj/effect/beam/i_beam/beams
var/olddir = 0
var/datum/component/redirect/listener
var/hearing_range = 3
/obj/item/assembly/infra/Initialize()
. = ..()
@@ -30,23 +32,27 @@
refreshBeam()
/obj/item/assembly/infra/Destroy()
STOP_PROCESSING(SSobj, src)
QDEL_LIST(beams)
return ..()
. = ..()
/obj/item/assembly/infra/describe()
return "The infrared trigger is [on?"on":"off"]."
/obj/item/assembly/infra/examine(mob/user)
..()
to_chat(user, "<span class='notice'>The infrared trigger is [on?"on":"off"].</span>")
/obj/item/assembly/infra/activate()
if(!..())
return 0//Cooldown check
return FALSE//Cooldown check
on = !on
refreshBeam()
update_icon()
return 1
return TRUE
/obj/item/assembly/infra/toggle_secure()
secured = !secured
if(secured)
START_PROCESSING(SSobj, src)
refreshBeam()
else
QDEL_LIST(beams)
STOP_PROCESSING(SSobj, src)
@@ -59,13 +65,20 @@
if(on)
add_overlay("infrared_on")
attached_overlays += "infrared_on"
if(visible && secured)
add_overlay("infrared_visible")
attached_overlays += "infrared_visible"
if(holder)
holder.update_icon()
return
/obj/item/assembly/infra/dropped()
refreshBeam()
. = ..()
if(holder)
holder_movement() //sync the dir of the device as well if it's contained in a TTV or an assembly holder
else
refreshBeam()
/obj/item/assembly/infra/process()
if(!on || !secured)
@@ -74,7 +87,15 @@
/obj/item/assembly/infra/proc/refreshBeam()
QDEL_LIST(beams)
if(throwing || !on || !secured || !(isturf(loc) || holder && isturf(holder.loc)))
if(throwing || !on || !secured)
return
if(holder)
if(holder.master) //incase the sensor is part of an assembly that's contained in another item, such as a single tank bomb
if(!holder.master.IsSpecialAssembly() || !isturf(holder.master.loc))
return
else if(!isturf(holder.loc)) //else just check where the holder is
return
else if(!isturf(loc)) //or just where the fuck we are in general
return
var/turf/T = get_turf(src)
var/_dir = dir
@@ -82,6 +103,11 @@
if(_T)
for(var/i in 1 to maxlength)
var/obj/effect/beam/i_beam/I = new(T)
if(istype(holder, /obj/item/assembly_holder))
var/obj/item/assembly_holder/assembly_holder = holder
I.icon_state = "[initial(I.icon_state)]_[(assembly_holder.a_left == src) ? "l":"r"]" //Sync the offset of the beam with the position of the sensor.
else if(istype(holder, /obj/item/transfer_valve))
I.icon_state = "[initial(I.icon_state)]_ttv"
I.density = TRUE
if(!I.Move(_T))
qdel(I)
@@ -96,6 +122,12 @@
_T = get_step(_T, _dir)
CHECK_TICK
/obj/item/assembly/infra/on_detach()
. = ..()
if(!.)
return
refreshBeam()
/obj/item/assembly/infra/attack_hand()
. = ..()
refreshBeam()
@@ -116,19 +148,17 @@
setDir(olddir)
olddir = null
/obj/item/assembly/infra/holder_movement()
if(!holder)
return 0
refreshBeam()
return 1
/obj/item/assembly/infra/proc/trigger_beam(atom/movable/AM, turf/location)
refreshBeam()
switchListener(location)
if(!secured || !on || next_activate > world.time)
return FALSE
pulse(0)
audible_message("[icon2html(src, hearers(src))] *beep* *beep*", null, 3)
pulse(FALSE)
audible_message("[icon2html(src, hearers(src))] *beep* *beep* *beep*", null, hearing_range)
for(var/CHM in get_hearers_in_view(hearing_range, src))
if(ismob(CHM))
var/mob/LM = CHM
LM.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE)
next_activate = world.time + 30
/obj/item/assembly/infra/proc/switchListener(turf/newloc)
@@ -144,7 +174,9 @@
. = ..()
if(is_secured(user))
user.set_machine(src)
var/dat = "<TT><B>Infrared Laser</B>\n<B>Status</B>: [on ? "<A href='?src=[REF(src)];state=0'>On</A>" : "<A href='?src=[REF(src)];state=1'>Off</A>"]<BR>\n<B>Visibility</B>: [visible ? "<A href='?src=[REF(src)];visible=0'>Visible</A>" : "<A href='?src=[REF(src)];visible=1'>Invisible</A>"]<BR>\n</TT>"
var/dat = "<TT><B>Infrared Laser</B></TT>"
dat += "<BR><B>Status</B>: [on ? "<A href='?src=[REF(src)];state=0'>On</A>" : "<A href='?src=[REF(src)];state=1'>Off</A>"]"
dat += "<BR><B>Visibility</B>: [visible ? "<A href='?src=[REF(src)];visible=0'>Visible</A>" : "<A href='?src=[REF(src)];visible=1'>Invisible</A>"]"
dat += "<BR><BR><A href='?src=[REF(src)];refresh=1'>Refresh</A>"
dat += "<BR><BR><A href='?src=[REF(src)];close=1'>Close</A>"
user << browse(dat, "window=infra")
@@ -163,6 +195,7 @@
refreshBeam()
if(href_list["visible"])
visible = !(visible)
update_icon()
refreshBeam()
if(href_list["close"])
usr << browse(null, "window=infra")
+12 -18
View File
@@ -2,17 +2,15 @@
name = "mousetrap"
desc = "A handy little spring-loaded trap for catching pesty rodents."
icon_state = "mousetrap"
item_state = "mousetrap"
materials = list(MAT_METAL=100)
attachable = 1
var/armed = 0
attachable = TRUE
var/armed = FALSE
/obj/item/assembly/mousetrap/examine(mob/user)
..()
if(armed)
to_chat(user, "The mousetrap is armed!")
else
to_chat(user, "The mousetrap is not armed.")
to_chat(user, "<span class='notice'>The pressure plate is [armed?"primed":"safe"].</span>")
/obj/item/assembly/mousetrap/activate()
if(..())
@@ -22,13 +20,9 @@
var/mob/living/carbon/human/user = usr
if((user.has_trait(TRAIT_DUMB) || user.has_trait(TRAIT_CLUMSY)) && prob(50))
to_chat(user, "<span class='warning'>Your hand slips, setting off the trigger!</span>")
pulse(0)
pulse(FALSE)
update_icon()
if(usr)
playsound(usr.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -3)
/obj/item/assembly/mousetrap/describe()
return "The pressure switch is [armed?"primed":"safe"]."
playsound(src, 'sound/weapons/handcuffs.ogg', 30, TRUE, -3)
/obj/item/assembly/mousetrap/update_icon()
if(armed)
@@ -45,10 +39,10 @@
if(ishuman(target))
var/mob/living/carbon/human/H = target
if(H.has_trait(TRAIT_PIERCEIMMUNE))
playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
playsound(src, 'sound/effects/snap.ogg', 50, TRUE)
armed = FALSE
update_icon()
pulse(0)
pulse(FALSE)
return FALSE
switch(type)
if("feet")
@@ -66,10 +60,10 @@
var/mob/living/simple_animal/mouse/M = target
visible_message("<span class='boldannounce'>SPLAT!</span>")
M.splat()
playsound(src.loc, 'sound/effects/snap.ogg', 50, 1)
playsound(src, 'sound/effects/snap.ogg', 50, TRUE)
armed = FALSE
update_icon()
pulse(0)
pulse(FALSE)
/obj/item/assembly/mousetrap/attack_self(mob/living/carbon/human/user)
@@ -87,7 +81,7 @@
to_chat(user, "<span class='notice'>You disarm [src].</span>")
armed = !armed
update_icon()
playsound(user.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -3)
playsound(src, 'sound/weapons/handcuffs.ogg', 30, TRUE, -3)
//ATTACK HAND IGNORING PARENT RETURN VALUE
@@ -145,4 +139,4 @@
/obj/item/assembly/mousetrap/armed
icon_state = "mousetraparmed"
armed = 1
armed = TRUE
+44 -31
View File
@@ -3,34 +3,36 @@
desc = "Used for scanning and alerting when someone enters a certain proximity."
icon_state = "prox"
materials = list(MAT_METAL=800, MAT_GLASS=200)
attachable = 1
attachable = TRUE
var/scanning = 0
var/timing = 0
var/scanning = FALSE
var/timing = FALSE
var/time = 10
var/sensitivity = 1
/obj/item/assembly/prox_sensor/proc/toggle_scan()
/obj/item/assembly/prox_sensor/proc/sense()
var/hearing_range = 3
/obj/item/assembly/prox_sensor/Initialize()
. = ..()
proximity_monitor = new(src, 0)
START_PROCESSING(SSobj, src)
/obj/item/assembly/prox_sensor/describe()
if(timing)
return "<span class='notice'>The proximity sensor is arming.</span>"
return "The proximity sensor is [scanning?"armed":"disarmed"]."
/obj/item/assembly/prox_sensor/Destroy()
STOP_PROCESSING(SSobj, src)
. = ..()
/obj/item/assembly/prox_sensor/examine(mob/user)
..()
to_chat(user, "<span class='notice'>The proximity sensor is [timing ? "arming" : (scanning ? "armed" : "disarmed")].</span>")
/obj/item/assembly/prox_sensor/activate()
if(!..())
return 0//Cooldown check
timing = !timing
return FALSE//Cooldown check
if(!scanning)
timing = !timing
else
scanning = FALSE
update_icon()
return 1
return TRUE
/obj/item/assembly/prox_sensor/toggle_secure()
secured = !secured
@@ -38,8 +40,10 @@
if(scanning)
toggle_scan()
proximity_monitor.host = src
timing = 0
timing = FALSE
STOP_PROCESSING(SSobj, src)
else
START_PROCESSING(SSobj, src)
proximity_monitor.host = loc
update_icon()
return secured
@@ -51,25 +55,31 @@
sense()
/obj/item/assembly/prox_sensor/sense()
/obj/item/assembly/prox_sensor/proc/sense()
if(!scanning || !secured || next_activate > world.time)
return 0
pulse(0)
audible_message("[icon2html(src, hearers(src))] *beep* *beep*", null, 3)
return FALSE
pulse(FALSE)
audible_message("[icon2html(src, hearers(src))] *beep* *beep* *beep*", null, hearing_range)
for(var/CHM in get_hearers_in_view(hearing_range, src))
if(ismob(CHM))
var/mob/LM = CHM
LM.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE)
next_activate = world.time + 30
return TRUE
/obj/item/assembly/prox_sensor/process()
if(timing)
time--
if(time <= 0)
timing = 0
toggle_scan(1)
time = initial(time)
if(!timing)
return
time--
if(time <= 0)
timing = FALSE
toggle_scan(TRUE)
time = initial(time)
/obj/item/assembly/prox_sensor/toggle_scan(scan)
/obj/item/assembly/prox_sensor/proc/toggle_scan(scan)
if(!secured)
return 0
return FALSE
scanning = scan
proximity_monitor.SetRange(scanning ? sensitivity : 0)
update_icon()
@@ -98,8 +108,11 @@
if(is_secured(user))
var/second = time % 60
var/minute = (time - second) / 60
var/dat = "<TT><B>Proximity Sensor</B>\n[(timing ? "<A href='?src=[REF(src)];time=0'>Arming</A>" : "<A href='?src=[REF(src)];time=1'>Not Arming</A>")] [minute]:[second]\n<A href='?src=[REF(src)];tp=-30'>-</A> <A href='?src=[REF(src)];tp=-1'>-</A> <A href='?src=[REF(src)];tp=1'>+</A> <A href='?src=[REF(src)];tp=30'>+</A>\n</TT>"
dat += "<BR><A href='?src=[REF(src)];scanning=[scanning?"0'>Armed":"1'>Unarmed"]</A> (Movement sensor active when armed!)"
var/dat = "<TT><B>Proximity Sensor</B></TT>"
if(!scanning)
dat += "<BR>[(timing ? "<A href='?src=[REF(src)];time=0'>Arming</A>" : "<A href='?src=[REF(src)];time=1'>Not Arming</A>")] [minute]:[second]"
dat += "<BR><A href='?src=[REF(src)];tp=-30'>-</A> <A href='?src=[REF(src)];tp=-1'>-</A> <A href='?src=[REF(src)];tp=1'>+</A> <A href='?src=[REF(src)];tp=30'>+</A>"
dat += "<BR><A href='?src=[REF(src)];scanning=[scanning?"0'>Armed":"1'>Unarmed (Movement sensor active when armed!)"]</A>"
dat += "<BR>Detection range: <A href='?src=[REF(src)];sense=down'>-</A> [sensitivity] <A href='?src=[REF(src)];sense=up'>+</A>"
dat += "<BR><BR><A href='?src=[REF(src)];refresh=1'>Refresh</A>"
dat += "<BR><BR><A href='?src=[REF(src)];close=1'>Close</A>"
+8 -8
View File
@@ -13,18 +13,18 @@
qdel(part2)
return ..()
/obj/item/assembly/shock_kit/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/wrench))
/obj/item/assembly/shock_kit/wrench_act(mob/living/user, obj/item/I)
to_chat(user, "<span class='notice'>You disassemble [src].</span>")
if(part1)
part1.forceMove(drop_location())
part2.forceMove(drop_location())
part1.master = null
part2.master = null
part1 = null
if(part2)
part2.forceMove(drop_location())
part2.master = null
part2 = null
qdel(src)
return
add_fingerprint(user)
return
qdel(src)
return TRUE
/obj/item/assembly/shock_kit/attack_self(mob/user)
part1.attack_self(user)
+30 -20
View File
@@ -7,17 +7,18 @@
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
materials = list(MAT_METAL=400, MAT_GLASS=120)
wires = WIRE_RECEIVE | WIRE_PULSE | WIRE_RADIO_PULSE | WIRE_RADIO_RECEIVE
attachable = 1
attachable = TRUE
var/code = DEFAULT_SIGNALER_CODE
var/frequency = FREQ_SIGNALER
var/delay = 0
var/datum/radio_frequency/radio_connection
var/suicider = null
var/hearing_range = 1
/obj/item/assembly/signaler/suicide_act(mob/living/carbon/user)
user.visible_message("<span class='suicide'>[user] eats \the [src]! If it is signaled, [user.p_they()] will die!</span>")
playsound(src, 'sound/items/eatfood.ogg', 50, 1)
playsound(src, 'sound/items/eatfood.ogg', 50, TRUE)
user.transferItemToLoc(src, user, TRUE)
suicider = user
return MANUAL_SUICIDE
@@ -27,15 +28,14 @@
user.adjustOxyLoss(200)//it sends an electrical pulse to their heart, killing them. or something.
user.death(0)
/obj/item/assembly/signaler/New()
..()
spawn(40)
set_frequency(frequency)
/obj/item/assembly/signaler/Initialize()
. = ..()
set_frequency(frequency)
/obj/item/assembly/signaler/Destroy()
SSradio.remove_object(src,frequency)
return ..()
. = ..()
/obj/item/assembly/signaler/activate()
if(!..())//cooldown processing
@@ -80,7 +80,7 @@ Code:
/obj/item/assembly/signaler/Topic(href, href_list)
..()
if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr))
if(!usr.canUseTopic(src, BE_CLOSE))
usr << browse(null, "window=radio")
onclose(usr, "radio")
return
@@ -111,7 +111,7 @@ Code:
var/obj/item/assembly/signaler/signaler2 = W
if(secured && signaler2.secured)
code = signaler2.code
frequency = signaler2.frequency
set_frequency(signaler2.frequency)
to_chat(user, "You transfer the frequency and code of \the [signaler2.name] to \the [name]")
..()
@@ -131,17 +131,22 @@ Code:
return
/obj/item/assembly/signaler/receive_signal(datum/signal/signal)
. = FALSE
if(!signal)
return 0
return
if(signal.data["code"] != code)
return 0
return
if(!(src.wires & WIRE_RADIO_RECEIVE))
return 0
return
if(suicider)
manual_suicide(suicider)
pulse(1)
audible_message("[icon2html(src, hearers(src))] *beep* *beep*", null, 1)
return
pulse(TRUE)
audible_message("[icon2html(src, hearers(src))] *beep* *beep* *beep*", null, hearing_range)
for(var/CHM in get_hearers_in_view(hearing_range, src))
if(ismob(CHM))
var/mob/LM = CHM
LM.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE)
return TRUE
/obj/item/assembly/signaler/proc/set_frequency(new_frequency)
@@ -161,10 +166,11 @@ Code:
/obj/item/assembly/signaler/reciever/activate()
toggle_safety()
return 1
return TRUE
/obj/item/assembly/signaler/reciever/describe()
return "The radio receiver is [on?"on":"off"]."
/obj/item/assembly/signaler/reciever/examine(mob/user)
..()
to_chat(user, "<span class='notice'>The radio receiver is [on?"on":"off"].</span>")
/obj/item/assembly/signaler/reciever/receive_signal(datum/signal/signal)
if(!on)
@@ -180,14 +186,16 @@ Code:
item_state = "electronic"
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
var/anomaly_type = /obj/effect/anomaly
/obj/item/assembly/signaler/anomaly/receive_signal(datum/signal/signal)
if(!signal)
return 0
return FALSE
if(signal.data["code"] != code)
return 0
return FALSE
for(var/obj/effect/anomaly/A in get_turf(src))
A.anomalyNeutralize()
return TRUE
/obj/item/assembly/signaler/anomaly/attack_self()
return
@@ -196,3 +204,5 @@ Code:
/obj/item/assembly/signaler/cyborg/attackby(obj/item/W, mob/user, params)
return
/obj/item/assembly/signaler/cyborg/screwdriver_act(mob/living/user, obj/item/I)
return
+33 -23
View File
@@ -3,12 +3,13 @@
desc = "Used to time things. Works well with contraptions which has to count down. Tick tock."
icon_state = "timer"
materials = list(MAT_METAL=500, MAT_GLASS=50)
attachable = 1
attachable = TRUE
var/timing = 0
var/timing = FALSE
var/time = 5
var/saved_time = 5
var/loop = 0
var/loop = FALSE
var/hearing_range = 3
/obj/item/assembly/timer/suicide_act(mob/living/user)
user.visible_message("<span class='suicide'>[user] looks at the timer and decides [user.p_their()] fate! It looks like [user.p_theyre()] going to commit suicide!</span>")
@@ -21,22 +22,24 @@
user.adjustOxyLoss(200)
user.death(0)
/obj/item/assembly/timer/New()
..()
/obj/item/assembly/timer/Initialize()
. = ..()
START_PROCESSING(SSobj, src)
/obj/item/assembly/timer/describe()
if(timing)
return "The timer is counting down from [time]!"
return "The timer is set for [time] seconds."
/obj/item/assembly/timer/Destroy()
STOP_PROCESSING(SSobj, src)
. = ..()
/obj/item/assembly/timer/examine(mob/user)
..()
to_chat(user, "<span class='notice'>The timer is [timing ? "counting down from [time]":"set for [time] seconds"].</span>")
/obj/item/assembly/timer/activate()
if(!..())
return 0//Cooldown check
return FALSE//Cooldown check
timing = !timing
update_icon()
return 1
return TRUE
/obj/item/assembly/timer/toggle_secure()
@@ -44,7 +47,7 @@
if(secured)
START_PROCESSING(SSobj, src)
else
timing = 0
timing = FALSE
STOP_PROCESSING(SSobj, src)
update_icon()
return secured
@@ -53,20 +56,25 @@
/obj/item/assembly/timer/proc/timer_end()
if(!secured || next_activate > world.time)
return FALSE
pulse(0)
audible_message("[icon2html(src, hearers(src))] *beep* *beep*", null, 3)
pulse(FALSE)
audible_message("[icon2html(src, hearers(src))] *beep* *beep* *beep*", null, hearing_range)
for(var/CHM in get_hearers_in_view(hearing_range, src))
if(ismob(CHM))
var/mob/LM = CHM
LM.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE)
if(loop)
timing = 1
timing = TRUE
update_icon()
/obj/item/assembly/timer/process()
if(timing)
time--
if(time <= 0)
timing = 0
timer_end()
time = saved_time
if(!timing)
return
time--
if(time <= 0)
timing = FALSE
timer_end()
time = saved_time
/obj/item/assembly/timer/update_icon()
@@ -84,7 +92,9 @@
if(is_secured(user))
var/second = time % 60
var/minute = (time - second) / 60
var/dat = "<TT><B>Timing Unit</B>\n[(timing ? "<A href='?src=[REF(src)];time=0'>Timing</A>" : "<A href='?src=[REF(src)];time=1'>Not Timing</A>")] [minute]:[second]\n<A href='?src=[REF(src)];tp=-30'>-</A> <A href='?src=[REF(src)];tp=-1'>-</A> <A href='?src=[REF(src)];tp=1'>+</A> <A href='?src=[REF(src)];tp=30'>+</A>\n</TT>"
var/dat = "<TT><B>Timing Unit</B></TT>"
dat += "<BR>[(timing ? "<A href='?src=[REF(src)];time=0'>Timing</A>" : "<A href='?src=[REF(src)];time=1'>Not Timing</A>")] [minute]:[second]"
dat += "<BR><A href='?src=[REF(src)];tp=-30'>-</A> <A href='?src=[REF(src)];tp=-1'>-</A> <A href='?src=[REF(src)];tp=1'>+</A> <A href='?src=[REF(src)];tp=30'>+</A>"
dat += "<BR><BR><A href='?src=[REF(src)];repeat=[(loop ? "0'>Stop repeating" : "1'>Set to repeat")]</A>"
dat += "<BR><BR><A href='?src=[REF(src)];refresh=1'>Refresh</A>"
dat += "<BR><BR><A href='?src=[REF(src)];close=1'>Close</A>"
@@ -95,7 +105,7 @@
/obj/item/assembly/timer/Topic(href, href_list)
..()
if(usr.incapacitated() || !in_range(loc, usr))
if(!usr.canUseTopic(src, BE_CLOSE))
usr << browse(null, "window=timer")
onclose(usr, "timer")
return
+43 -34
View File
@@ -1,14 +1,19 @@
#define INCLUSIVE_MODE 1
#define EXCLUSIVE_MODE 2
#define RECOGNIZER_MODE 3
#define VOICE_SENSOR_MODE 4
/obj/item/assembly/voice
name = "voice analyzer"
desc = "A small electronic device able to record a voice sample, and send a signal when that sample is repeated."
icon_state = "voice"
materials = list(MAT_METAL=500, MAT_GLASS=50)
flags_1 = HEAR_1
attachable = 1
attachable = TRUE
verb_say = "beeps"
verb_ask = "beeps"
verb_exclaim = "beeps"
var/listening = 0
var/listening = FALSE
var/recorded = "" //the activation message
var/mode = 1
var/static/list/modes = list("inclusive",
@@ -32,60 +37,64 @@
/obj/item/assembly/voice/proc/record_speech(atom/movable/speaker, raw_message, datum/language/message_language)
switch(mode)
if(1)
if(INCLUSIVE_MODE)
recorded = raw_message
listening = 0
listening = FALSE
say("Activation message is '[recorded]'.", message_language)
if(2)
if(EXCLUSIVE_MODE)
recorded = raw_message
listening = 0
listening = FALSE
say("Activation message is '[recorded]'.", message_language)
if(3)
if(RECOGNIZER_MODE)
recorded = speaker.GetVoice()
listening = 0
listening = FALSE
say("Your voice pattern is saved.", message_language)
if(4)
if(VOICE_SENSOR_MODE)
if(length(raw_message))
addtimer(CALLBACK(src, .proc/pulse, 0), 10)
/obj/item/assembly/voice/proc/check_activation(atom/movable/speaker, raw_message)
. = 0
. = FALSE
switch(mode)
if(1)
if(INCLUSIVE_MODE)
if(findtext(raw_message, recorded))
. = 1
if(2)
. = TRUE
if(EXCLUSIVE_MODE)
if(raw_message == recorded)
. = 1
if(3)
. = TRUE
if(RECOGNIZER_MODE)
if(speaker.GetVoice() == recorded)
. = 1
if(4)
. = TRUE
if(VOICE_SENSOR_MODE)
if(length(raw_message))
. = 1
. = TRUE
/obj/item/assembly/voice/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/multitool))
mode %= modes.len
mode++
to_chat(user, "You set [src] into a [modes[mode]] mode.")
listening = 0
recorded = ""
else
return ..()
/obj/item/assembly/voice/multitool_act(mob/living/user, obj/item/I)
mode %= modes.len
mode++
to_chat(user, "<span class='notice'>You set [src] into [modes[mode]] mode.</span>")
listening = FALSE
recorded = ""
return TRUE
/obj/item/assembly/voice/activate()
if(secured)
if(!holder)
listening = !listening
say("[listening ? "Now" : "No longer"] recording input.")
if(!secured || holder)
return FALSE
listening = !listening
say("[listening ? "Now" : "No longer"] recording input.")
return TRUE
/obj/item/assembly/voice/attack_self(mob/user)
if(!user)
return 0
return FALSE
activate()
return 1
return TRUE
/obj/item/assembly/voice/toggle_secure()
. = ..()
listening = 0
listening = FALSE
#undef INCLUSIVE_MODE
#undef EXCLUSIVE_MODE
#undef RECOGNIZER_MODE
#undef VOICE_SENSOR_MODE
@@ -191,7 +191,7 @@
//fusion: a terrible idea that was fun but broken. Now reworked to be less broken and more interesting. Again.
/datum/gas_reaction/fusion
exclude = FALSE
exclude = TRUE
priority = 2
name = "Plasmic Fusion"
id = "fusion"
@@ -34,8 +34,10 @@ Iconnery
var/turf/T = loc
if(level == 2 || !T.intact)
showpipe = TRUE
plane = GAME_PLANE
else
showpipe = FALSE
plane = FLOOR_PLANE
if(!showpipe)
return //no need to update the pipes if they aren't showing
+1 -1
View File
@@ -101,7 +101,7 @@
export_types = list(/obj/machinery/iv_drip)
/datum/export/large/barrier
cost = 325
cost = 100
unit_name = "security barrier"
export_types = list(/obj/item/grenade/barrier, /obj/structure/barricade/security)
+3 -2
View File
@@ -1649,8 +1649,9 @@
. = ..()
if(prob(50))
var/mob/living/simple_animal/pet/dog/corgi/D = locate() in .
qdel(D)
new /mob/living/simple_animal/pet/dog/corgi/Lisa(.)
if(D.gender == FEMALE)
qdel(D)
new /mob/living/simple_animal/pet/dog/corgi/Lisa(.)
/datum/supply_pack/critter/cow
name = "Cow Crate"
+243 -62
View File
@@ -157,12 +157,14 @@ GLOBAL_LIST_EMPTY(asset_datums)
//get an assetdatum or make a new one
/proc/get_asset_datum(var/type)
if (!(type in GLOB.asset_datums))
return new type()
return GLOB.asset_datums[type]
return GLOB.asset_datums[type] || new type()
/datum/asset
var/_abstract = /datum/asset
/datum/asset/New()
GLOB.asset_datums[type] = src
register()
/datum/asset/proc/register()
return
@@ -170,20 +172,173 @@ GLOBAL_LIST_EMPTY(asset_datums)
/datum/asset/proc/send(client)
return
//If you don't need anything complicated.
/datum/asset/simple
_abstract = /datum/asset/simple
var/assets = list()
var/verify = FALSE
/datum/asset/simple/register()
for(var/asset_name in assets)
register_asset(asset_name, assets[asset_name])
/datum/asset/simple/send(client)
send_asset_list(client,assets,verify)
// For registering or sending multiple others at once
/datum/asset/group
_abstract = /datum/asset/group
var/list/children
/datum/asset/group/register()
for(var/type in children)
get_asset_datum(type)
/datum/asset/group/send(client/C)
for(var/type in children)
var/datum/asset/A = get_asset_datum(type)
A.send(C)
// spritesheet implementation - coalesces various icons into a single .png file
// and uses CSS to select icons out of that file - saves on transferring some
// 1400-odd individual PNG files
#define SPR_SIZE 1
#define SPR_IDX 2
#define SPRSZ_COUNT 1
#define SPRSZ_ICON 2
#define SPRSZ_STRIPPED 3
/datum/asset/spritesheet
_abstract = /datum/asset/spritesheet
var/name
var/list/sizes = list() // "32x32" -> list(10, icon/normal, icon/stripped)
var/list/sprites = list() // "foo_bar" -> list("32x32", 5)
var/verify = FALSE
/datum/asset/spritesheet/register()
if (!name)
CRASH("spritesheet [type] cannot register without a name")
ensure_stripped()
var/res_name = "spritesheet_[name].css"
var/fname = "data/spritesheets/[res_name]"
call("rust_g", "file_write")(generate_css(), fname)
register_asset(res_name, file(fname))
for(var/size_id in sizes)
var/size = sizes[size_id]
register_asset("[name]_[size_id].png", size[SPRSZ_STRIPPED])
/datum/asset/spritesheet/send(client/C)
if (!name)
return
var/all = list("spritesheet_[name].css")
for(var/size_id in sizes)
all += "[name]_[size_id].png"
send_asset_list(C, all, verify)
/datum/asset/spritesheet/proc/ensure_stripped(sizes_to_strip = sizes)
for(var/size_id in sizes_to_strip)
var/size = sizes[size_id]
if (size[SPRSZ_STRIPPED])
continue
// save flattened version
var/fname = "data/spritesheets/[name]_[size_id].png"
fcopy(size[SPRSZ_ICON], fname)
var/error = call("rust_g", "dmi_strip_metadata")(fname)
if(length(error))
stack_trace("Failed to strip [name]_[size_id].png: [error]")
size[SPRSZ_STRIPPED] = icon(fname)
/datum/asset/spritesheet/proc/generate_css()
var/list/out = list()
for (var/size_id in sizes)
var/size = sizes[size_id]
var/icon/tiny = size[SPRSZ_ICON]
out += ".[name][size_id]{display:inline-block;width:[tiny.Width()]px;height:[tiny.Height()]px;background:url('[name]_[size_id].png') no-repeat;}"
for (var/sprite_id in sprites)
var/sprite = sprites[sprite_id]
var/size_id = sprite[SPR_SIZE]
var/idx = sprite[SPR_IDX]
var/size = sizes[size_id]
var/icon/tiny = size[SPRSZ_ICON]
var/icon/big = size[SPRSZ_STRIPPED]
var/per_line = big.Width() / tiny.Width()
var/x = (idx % per_line) * tiny.Width()
var/y = round(idx / per_line) * tiny.Height()
out += ".[name][size_id].[sprite_id]{background-position:-[x]px -[y]px;}"
return out.Join("\n")
/datum/asset/spritesheet/proc/Insert(sprite_name, icon/I, icon_state="", dir=SOUTH, frame=1, moving=FALSE)
I = icon(I, icon_state=icon_state, dir=dir, frame=frame, moving=moving)
if (!I || !length(icon_states(I))) // that direction or state doesn't exist
return
var/size_id = "[I.Width()]x[I.Height()]"
var/size = sizes[size_id]
if (sprites[sprite_name])
CRASH("duplicate sprite \"[sprite_name]\" in sheet [name] ([type])")
if (size)
var/position = size[SPRSZ_COUNT]++
var/icon/sheet = size[SPRSZ_ICON]
size[SPRSZ_STRIPPED] = null
sheet.Insert(I, icon_state=sprite_name)
sprites[sprite_name] = list(size_id, position)
else
sizes[size_id] = size = list(1, I, null)
sprites[sprite_name] = list(size_id, 0)
/datum/asset/spritesheet/proc/InsertAll(prefix, icon/I, list/directions)
if (length(prefix))
prefix = "[prefix]-"
if (!directions)
directions = list(SOUTH)
for (var/icon_state_name in icon_states(I))
for (var/direction in directions)
var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]-" : ""
Insert("[prefix][prefix2][icon_state_name]", I, icon_state=icon_state_name, dir=direction)
/datum/asset/spritesheet/proc/css_tag()
return {"<link rel="stylesheet" href="spritesheet_[name].css" />"}
/datum/asset/spritesheet/proc/icon_tag(sprite_name)
var/sprite = sprites[sprite_name]
if (!sprite)
return null
var/size_id = sprite[SPR_SIZE]
return {"<span class="[name][size_id] [sprite_name]"></span>"}
#undef SPR_SIZE
#undef SPR_IDX
#undef SPRSZ_COUNT
#undef SPRSZ_ICON
#undef SPRSZ_STRIPPED
/datum/asset/spritesheet/simple
_abstract = /datum/asset/spritesheet/simple
var/list/assets
/datum/asset/spritesheet/simple/register()
for (var/key in assets)
Insert(key, assets[key])
..()
//Generates assets based on iconstates of a single icon
/datum/asset/simple/icon_states
_abstract = /datum/asset/simple/icon_states
var/icon
var/list/directions = list(SOUTH)
var/frame = 1
@@ -209,6 +364,7 @@ GLOBAL_LIST_EMPTY(asset_datums)
register_asset(asset_name, asset)
/datum/asset/simple/icon_states/multiple_icons
_abstract = /datum/asset/simple/icon_states/multiple_icons
var/list/icons
/datum/asset/simple/icon_states/multiple_icons/register()
@@ -260,50 +416,52 @@ GLOBAL_LIST_EMPTY(asset_datums)
"smmon_6.gif" = 'icons/program_icons/smmon_6.gif'
)
/datum/asset/simple/pda
/datum/asset/spritesheet/simple/pda
name = "pda"
assets = list(
"pda_atmos.png" = 'icons/pda_icons/pda_atmos.png',
"pda_back.png" = 'icons/pda_icons/pda_back.png',
"pda_bell.png" = 'icons/pda_icons/pda_bell.png',
"pda_blank.png" = 'icons/pda_icons/pda_blank.png',
"pda_boom.png" = 'icons/pda_icons/pda_boom.png',
"pda_bucket.png" = 'icons/pda_icons/pda_bucket.png',
"pda_medbot.png" = 'icons/pda_icons/pda_medbot.png',
"pda_floorbot.png" = 'icons/pda_icons/pda_floorbot.png',
"pda_cleanbot.png" = 'icons/pda_icons/pda_cleanbot.png',
"pda_crate.png" = 'icons/pda_icons/pda_crate.png',
"pda_cuffs.png" = 'icons/pda_icons/pda_cuffs.png',
"pda_eject.png" = 'icons/pda_icons/pda_eject.png',
"pda_flashlight.png" = 'icons/pda_icons/pda_flashlight.png',
"pda_honk.png" = 'icons/pda_icons/pda_honk.png',
"pda_mail.png" = 'icons/pda_icons/pda_mail.png',
"pda_medical.png" = 'icons/pda_icons/pda_medical.png',
"pda_menu.png" = 'icons/pda_icons/pda_menu.png',
"pda_mule.png" = 'icons/pda_icons/pda_mule.png',
"pda_notes.png" = 'icons/pda_icons/pda_notes.png',
"pda_power.png" = 'icons/pda_icons/pda_power.png',
"pda_rdoor.png" = 'icons/pda_icons/pda_rdoor.png',
"pda_reagent.png" = 'icons/pda_icons/pda_reagent.png',
"pda_refresh.png" = 'icons/pda_icons/pda_refresh.png',
"pda_scanner.png" = 'icons/pda_icons/pda_scanner.png',
"pda_signaler.png" = 'icons/pda_icons/pda_signaler.png',
"pda_status.png" = 'icons/pda_icons/pda_status.png',
"pda_dronephone.png" = 'icons/pda_icons/pda_dronephone.png'
"atmos" = 'icons/pda_icons/pda_atmos.png',
"back" = 'icons/pda_icons/pda_back.png',
"bell" = 'icons/pda_icons/pda_bell.png',
"blank" = 'icons/pda_icons/pda_blank.png',
"boom" = 'icons/pda_icons/pda_boom.png',
"bucket" = 'icons/pda_icons/pda_bucket.png',
"medbot" = 'icons/pda_icons/pda_medbot.png',
"floorbot" = 'icons/pda_icons/pda_floorbot.png',
"cleanbot" = 'icons/pda_icons/pda_cleanbot.png',
"crate" = 'icons/pda_icons/pda_crate.png',
"cuffs" = 'icons/pda_icons/pda_cuffs.png',
"eject" = 'icons/pda_icons/pda_eject.png',
"flashlight" = 'icons/pda_icons/pda_flashlight.png',
"honk" = 'icons/pda_icons/pda_honk.png',
"mail" = 'icons/pda_icons/pda_mail.png',
"medical" = 'icons/pda_icons/pda_medical.png',
"menu" = 'icons/pda_icons/pda_menu.png',
"mule" = 'icons/pda_icons/pda_mule.png',
"notes" = 'icons/pda_icons/pda_notes.png',
"power" = 'icons/pda_icons/pda_power.png',
"rdoor" = 'icons/pda_icons/pda_rdoor.png',
"reagent" = 'icons/pda_icons/pda_reagent.png',
"refresh" = 'icons/pda_icons/pda_refresh.png',
"scanner" = 'icons/pda_icons/pda_scanner.png',
"signaler" = 'icons/pda_icons/pda_signaler.png',
"status" = 'icons/pda_icons/pda_status.png',
"dronephone" = 'icons/pda_icons/pda_dronephone.png'
)
/datum/asset/simple/paper
/datum/asset/spritesheet/simple/paper
name = "paper"
assets = list(
"large_stamp-clown.png" = 'icons/stamp_icons/large_stamp-clown.png',
"large_stamp-deny.png" = 'icons/stamp_icons/large_stamp-deny.png',
"large_stamp-ok.png" = 'icons/stamp_icons/large_stamp-ok.png',
"large_stamp-hop.png" = 'icons/stamp_icons/large_stamp-hop.png',
"large_stamp-cmo.png" = 'icons/stamp_icons/large_stamp-cmo.png',
"large_stamp-ce.png" = 'icons/stamp_icons/large_stamp-ce.png',
"large_stamp-hos.png" = 'icons/stamp_icons/large_stamp-hos.png',
"large_stamp-rd.png" = 'icons/stamp_icons/large_stamp-rd.png',
"large_stamp-cap.png" = 'icons/stamp_icons/large_stamp-cap.png',
"large_stamp-qm.png" = 'icons/stamp_icons/large_stamp-qm.png',
"large_stamp-law.png" = 'icons/stamp_icons/large_stamp-law.png'
"stamp-clown" = 'icons/stamp_icons/large_stamp-clown.png',
"stamp-deny" = 'icons/stamp_icons/large_stamp-deny.png',
"stamp-ok" = 'icons/stamp_icons/large_stamp-ok.png',
"stamp-hop" = 'icons/stamp_icons/large_stamp-hop.png',
"stamp-cmo" = 'icons/stamp_icons/large_stamp-cmo.png',
"stamp-ce" = 'icons/stamp_icons/large_stamp-ce.png',
"stamp-hos" = 'icons/stamp_icons/large_stamp-hos.png',
"stamp-rd" = 'icons/stamp_icons/large_stamp-rd.png',
"stamp-cap" = 'icons/stamp_icons/large_stamp-cap.png',
"stamp-qm" = 'icons/stamp_icons/large_stamp-qm.png',
"stamp-law" = 'icons/stamp_icons/large_stamp-law.png'
)
/datum/asset/simple/IRV
@@ -335,10 +493,22 @@ GLOBAL_LIST_EMPTY(asset_datums)
"changelog.css" = 'html/changelog.css'
)
/datum/asset/simple/goonchat
/datum/asset/group/goonchat
children = list(
/datum/asset/simple/jquery,
/datum/asset/simple/goonchat,
/datum/asset/spritesheet/goonchat
)
/datum/asset/simple/jquery
verify = FALSE
assets = list(
"jquery.min.js" = 'code/modules/goonchat/browserassets/js/jquery.min.js',
)
/datum/asset/simple/goonchat
verify = FALSE
assets = list(
"json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js',
"errorHandler.js" = 'code/modules/goonchat/browserassets/js/errorHandler.js',
"browserOutput.js" = 'code/modules/goonchat/browserassets/js/browserOutput.js',
@@ -350,6 +520,24 @@ GLOBAL_LIST_EMPTY(asset_datums)
"browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css',
)
/datum/asset/spritesheet/goonchat
name = "chat"
/datum/asset/spritesheet/goonchat/register()
InsertAll("emoji", 'icons/emoji.dmi')
// pre-loading all lanugage icons also helps to avoid meta
InsertAll("language", 'icons/misc/language.dmi')
// catch languages which are pulling icons from another file
for(var/path in typesof(/datum/language))
var/datum/language/L = path
var/icon = initial(L.icon)
if (icon != 'icons/misc/language.dmi')
var/icon_state = initial(L.icon_state)
Insert("language-[icon_state]", icon, icon_state=icon_state)
..()
/datum/asset/simple/permissions
assets = list(
"padlock.png" = 'html/padlock.png'
@@ -362,26 +550,19 @@ GLOBAL_LIST_EMPTY(asset_datums)
var/datum/language/L = new path ()
L.get_icon()
/datum/asset/simple/icon_states/emojis
icon = 'icons/emoji.dmi'
generic_icon_names = TRUE
/datum/asset/spritesheet/pipes
name = "pipes"
/datum/asset/simple/icon_states/multiple_icons/pipes
icons = list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi', 'icons/obj/atmospherics/pipes/transit_tube.dmi')
prefix = "pipe"
/datum/asset/simple/icon_states/multiple_icons/pipes/New()
directions = GLOB.alldirs
/datum/asset/spritesheet/pipes/register()
for (var/each in list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi', 'icons/obj/atmospherics/pipes/transit_tube.dmi'))
InsertAll("", each, GLOB.alldirs)
..()
/datum/asset/simple/icon_states/multiple_icons/pipes/register()
..()
var/meter = icon('icons/obj/atmospherics/pipes/simple.dmi', "meterX", SOUTH, frame, movement_states)
if(meter)
register_asset(sanitize_filename("[prefix].south.meterX.png"), fcopy_rsc(meter))
// Representative icons for each research design
/datum/asset/simple/research_designs/register()
/datum/asset/spritesheet/research_designs
name = "design"
/datum/asset/spritesheet/research_designs/register()
for (var/path in subtypesof(/datum/design))
var/datum/design/D = path
@@ -401,7 +582,6 @@ GLOBAL_LIST_EMPTY(asset_datums)
if (machine)
item = machine
var/icon_file = initial(item.icon)
var/all_states = icon_states(icon_file)
var/icon/I = icon(icon_file, initial(item.icon_state), SOUTH)
// computers (and snowflakes) get their screen and keyboard sprites
@@ -409,10 +589,11 @@ GLOBAL_LIST_EMPTY(asset_datums)
var/obj/machinery/computer/C = item
var/screen = initial(C.icon_screen)
var/keyboard = initial(C.icon_keyboard)
var/all_states = icon_states(icon_file)
if (screen && (screen in all_states))
I.Blend(icon(icon_file, screen, SOUTH), ICON_OVERLAY)
if (keyboard && (keyboard in all_states))
I.Blend(icon(icon_file, keyboard, SOUTH), ICON_OVERLAY)
assets["design_[initial(D.id)].png"] = I
Insert(initial(D.id), I)
return ..()
+13 -1
View File
@@ -165,6 +165,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
return var_name != NAMEOF(src, holder) && ..()
/client/New(TopicData)
world.SetConfig("APP/admin", ckey, "role=admin") //CITADEL EDIT - Allows admins to reboot in OOM situations
var/tdata = TopicData //save this for later use
chatOutput = new /datum/chatOutput(src)
TopicData = null //Prevent calls to client.Topic from connect
@@ -179,10 +180,15 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
var/connecting_admin = FALSE //because de-admined admins connecting should be treated like admins.
//Admin Authorisation
holder = GLOB.admin_datums[ckey]
var/debug_tools_allowed = FALSE //CITADEL EDIT
if(holder)
GLOB.admins |= src
holder.owner = src
connecting_admin = TRUE
//CITADEL EDIT
if(check_rights_for(src, R_DEBUG))
debug_tools_allowed = TRUE
//END CITADEL EDIT
else if(GLOB.deadmins[ckey])
verbs += /client/proc/readmin
connecting_admin = TRUE
@@ -197,6 +203,12 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
to_chat(world, "Autoadmin rank not found")
else
new /datum/admins(autorank, ckey)
//CITADEL EDIT
if(check_rights_for(src, R_DEBUG)) //check if autoadmin gave us it
debug_tools_allowed = TRUE
if(!debug_tools_allowed)
world.SetConfig("APP/admin", ckey, null)
//END CITADEL EDIT
if(CONFIG_GET(flag/enable_localhost_rank) && !connecting_admin)
var/localhost_addresses = list("127.0.0.1", "::1")
if(isnull(address) || (address in localhost_addresses))
@@ -381,7 +393,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
winset(src, "[topmenu.type]", "parent=menu;name=[url_encode(topmenuname)]")
var/list/entries = topmenu.Generate_list(src)
for (var/child in entries)
winset(src, "[url_encode(child)]", "[entries[child]]")
winset(src, "[child]", "[entries[child]]")
if (!ispath(child, /datum/verbs/menu))
var/atom/verb/verbpath = child
if (copytext(verbpath.name,1,2) != "@")
+91 -85
View File
@@ -83,12 +83,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
//Mob preview
var/icon/preview_icon = null
//Trait list
var/list/positive_traits = list()
var/list/negative_traits = list()
var/list/neutral_traits = list()
var/list/all_traits = list()
var/list/character_traits = list()
//Quirk list
var/list/positive_quirks = list()
var/list/negative_quirks = list()
var/list/neutral_quirks = list()
var/list/all_quirks = list()
var/list/character_quirks = list()
//Jobs, uses bitflags
var/job_civilian_high = 0
@@ -120,6 +120,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/parallax
var/ambientocclusion = TRUE
var/uplink_spawn_loc = UPLINK_PDA
var/list/exp = list()
@@ -193,9 +195,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<center><h2>Occupation Choices</h2>"
dat += "<a href='?_src_=prefs;preference=job;task=menu'>Set Occupation Preferences</a><br></center>"
if(CONFIG_GET(flag/roundstart_traits))
dat += "<center><h2>Trait Setup</h2>"
dat += "<a href='?_src_=prefs;preference=trait;task=menu'>Configure Traits</a><br></center>"
dat += "<center><b>Current traits:</b> [all_traits.len ? all_traits.Join(", ") : "None"]</center>"
dat += "<center><h2>Quirk Setup</h2>"
dat += "<a href='?_src_=prefs;preference=trait;task=menu'>Configure Quirks</a><br></center>"
dat += "<center><b>Current quirks:</b> [all_quirks.len ? all_quirks.Join(", ") : "None"]</center>"
dat += "<h2>Identity</h2>"
dat += "<table width='100%'><tr><td width='75%' valign='top'>"
if(jobban_isbanned(user, "appearance"))
@@ -490,6 +492,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "High"
dat += "</a><br>"
dat += "<b>Ambient Occlusion:</b> <a href='?_src_=prefs;preference=ambientocclusion'>[ambientocclusion ? "Enabled" : "Disabled"]</a><br>"
dat += "</td><td width='300px' height='300px' valign='top'>"
dat += "<h2>Special Role Settings</h2>"
@@ -855,72 +859,72 @@ GLOBAL_LIST_EMPTY(preferences_datums)
return job_engsec_low
return 0
/datum/preferences/proc/SetTraits(mob/user)
if(!SStraits)
to_chat(user, "<span class='danger'>The trait subsystem is still initializing! Try again in a minute.</span>")
/datum/preferences/proc/SetQuirks(mob/user)
if(!SSquirks)
to_chat(user, "<span class='danger'>The quirk subsystem is still initializing! Try again in a minute.</span>")
return
var/list/dat = list()
if(!SStraits.traits.len)
dat += "The trait subsystem hasn't finished initializing, please hold..."
if(!SSquirks.quirks.len)
dat += "The quirk subsystem hasn't finished initializing, please hold..."
dat += "<center><a href='?_src_=prefs;preference=trait;task=close'>Done</a></center><br>"
else
dat += "<center><b>Choose trait setup</b></center><br>"
dat += "<div align='center'>Left-click to add or remove traits. You need one negative trait for every positive trait.<br>\
Traits are applied at roundstart and cannot normally be removed.</div>"
dat += "<center><b>Choose quirk setup</b></center><br>"
dat += "<div align='center'>Left-click to add or remove quirks. You need negative quirks to have positive ones.<br>\
Quirks are applied at roundstart and cannot normally be removed.</div>"
dat += "<center><a href='?_src_=prefs;preference=trait;task=close'>Done</a></center>"
dat += "<hr>"
dat += "<center><b>Current traits:</b> [all_traits.len ? all_traits.Join(", ") : "None"]</center>"
dat += "<center>[all_traits.len] / [MAX_TRAITS] max traits<br>\
<b>Trait balance remaining:</b> [GetTraitBalance()]</center><br>"
for(var/V in SStraits.traits)
var/datum/trait/T = SStraits.traits[V]
var/trait_name = initial(T.name)
var/has_trait
var/trait_cost = initial(T.value) * -1
dat += "<center><b>Current quirks:</b> [all_quirks.len ? all_quirks.Join(", ") : "None"]</center>"
dat += "<center>[positive_quirks.len] / [MAX_QUIRKS] max positive quirks<br>\
<b>Quirk balance remaining:</b> [GetQuirkBalance()]</center><br>"
for(var/V in SSquirks.quirks)
var/datum/quirk/T = SSquirks.quirks[V]
var/quirk_name = initial(T.name)
var/has_quirk
var/quirk_cost = initial(T.value) * -1
var/lock_reason = "This trait is unavailable."
var/trait_conflict = FALSE
for(var/_V in all_traits)
if(_V == trait_name)
has_trait = TRUE
if(initial(T.mood_trait) && CONFIG_GET(flag/disable_human_mood))
var/quirk_conflict = FALSE
for(var/_V in all_quirks)
if(_V == quirk_name)
has_quirk = TRUE
if(initial(T.mood_quirk) && CONFIG_GET(flag/disable_human_mood))
lock_reason = "Mood is disabled."
trait_conflict = TRUE
if(has_trait)
if(trait_conflict)
all_traits -= trait_name
has_trait = FALSE
quirk_conflict = TRUE
if(has_quirk)
if(quirk_conflict)
all_quirks -= quirk_name
has_quirk = FALSE
else
trait_cost *= -1 //invert it back, since we'd be regaining this amount
if(trait_cost > 0)
trait_cost = "+[trait_cost]"
quirk_cost *= -1 //invert it back, since we'd be regaining this amount
if(quirk_cost > 0)
quirk_cost = "+[quirk_cost]"
var/font_color = "#AAAAFF"
if(initial(T.value) != 0)
font_color = initial(T.value) > 0 ? "#AAFFAA" : "#FFAAAA"
if(trait_conflict)
dat += "<font color='[font_color]'>[trait_name]</font> - [initial(T.desc)] \
if(quirk_conflict)
dat += "<font color='[font_color]'>[quirk_name]</font> - [initial(T.desc)] \
<font color='red'><b>LOCKED: [lock_reason]</b></font><br>"
else
if(has_trait)
dat += "<b><font color='[font_color]'>[trait_name]</font></b> - [initial(T.desc)] \
<a href='?_src_=prefs;preference=trait;task=update;trait=[trait_name]'>[has_trait ? "Lose" : "Take"] ([trait_cost] pts.)</a><br>"
if(has_quirk)
dat += "<b><font color='[font_color]'>[quirk_name]</font></b> - [initial(T.desc)] \
<a href='?_src_=prefs;preference=trait;task=update;trait=[quirk_name]'>[has_quirk ? "Lose" : "Take"] ([quirk_cost] pts.)</a><br>"
else
dat += "<font color='[font_color]'>[trait_name]</font> - [initial(T.desc)] \
<a href='?_src_=prefs;preference=trait;task=update;trait=[trait_name]'>[has_trait ? "Lose" : "Take"] ([trait_cost] pts.)</a><br>"
dat += "<font color='[font_color]'>[quirk_name]</font> - [initial(T.desc)] \
<a href='?_src_=prefs;preference=trait;task=update;trait=[quirk_name]'>[has_quirk ? "Lose" : "Take"] ([quirk_cost] pts.)</a><br>"
dat += "<br><center><a href='?_src_=prefs;preference=trait;task=reset'>Reset Traits</a></center>"
user << browse(null, "window=preferences")
var/datum/browser/popup = new(user, "mob_occupation", "<div align='center'>Trait Preferences</div>", 900, 600) //no reason not to reuse the occupation window, as it's cleaner that way
var/datum/browser/popup = new(user, "mob_occupation", "<div align='center'>Quirk Preferences</div>", 900, 600) //no reason not to reuse the occupation window, as it's cleaner that way
popup.set_window_options("can_close=0")
popup.set_content(dat.Join())
popup.open(0)
return
/datum/preferences/proc/GetTraitBalance()
/datum/preferences/proc/GetQuirkBalance()
var/bal = 0
for(var/V in all_traits)
var/datum/trait/T = SStraits.traits[V]
for(var/V in all_quirks)
var/datum/quirk/T = SSquirks.quirks[V]
bal -= initial(T.value)
return bal
@@ -977,55 +981,49 @@ GLOBAL_LIST_EMPTY(preferences_datums)
user << browse(null, "window=mob_occupation")
ShowChoices(user)
if("update")
var/trait = href_list["trait"]
if(!SStraits.traits[trait])
var/quirk = href_list["trait"]
if(!SSquirks.quirks[quirk])
return
var/value = SStraits.trait_points[trait]
var/value = SSquirks.quirk_points[quirk]
if(value == 0)
if(trait in neutral_traits)
neutral_traits -= trait
all_traits -= trait
if(quirk in neutral_quirks)
neutral_quirks -= quirk
all_quirks -= quirk
else
if(all_traits.len >= MAX_TRAITS)
to_chat(user, "<span class='warning'>You can't have more than [MAX_TRAITS] traits!</span>")
return
neutral_traits += trait
all_traits += trait
neutral_quirks += quirk
all_quirks += quirk
else
var/balance = GetTraitBalance()
if(trait in positive_traits)
positive_traits -= trait
all_traits -= trait
else if(trait in negative_traits)
var/balance = GetQuirkBalance()
if(quirk in positive_quirks)
positive_quirks -= quirk
all_quirks -= quirk
else if(quirk in negative_quirks)
if(balance + value < 0)
to_chat(user, "<span class='warning'>Refunding this would cause you to go below your balance!</span>")
return
negative_traits -= trait
all_traits -= trait
negative_quirks -= quirk
all_quirks -= quirk
else if(value > 0)
if(all_traits.len >= MAX_TRAITS)
to_chat(user, "<span class='warning'>You can't have more than [MAX_TRAITS] traits!</span>")
if(positive_quirks.len >= MAX_QUIRKS)
to_chat(user, "<span class='warning'>You can't have more than [MAX_QUIRKS] positive quirks!</span>")
return
if(balance - value < 0)
to_chat(user, "<span class='warning'>You don't have enough balance to gain this trait!</span>")
to_chat(user, "<span class='warning'>You don't have enough balance to gain this quirk!</span>")
return
positive_traits += trait
all_traits += trait
positive_quirks += quirk
all_quirks += quirk
else
if(all_traits.len >= MAX_TRAITS)
to_chat(user, "<span class='warning'>You can't have more than [MAX_TRAITS] traits!</span>")
return
negative_traits += trait
all_traits += trait
SetTraits(user)
negative_quirks += quirk
all_quirks += quirk
SetQuirks(user)
if("reset")
all_traits = list()
positive_traits = list()
negative_traits = list()
neutral_traits = list()
SetTraits(user)
all_quirks = list()
positive_quirks = list()
negative_quirks = list()
neutral_quirks = list()
SetQuirks(user)
else
SetTraits(user)
SetQuirks(user)
return TRUE
switch(href_list["task"])
@@ -1535,6 +1533,14 @@ GLOBAL_LIST_EMPTY(preferences_datums)
cit_toggles ^= DIGESTION_NOISES
//END CITADEL EDIT
if("ambientocclusion")
ambientocclusion = !ambientocclusion
if(parent && parent.screen && parent.screen.len)
var/obj/screen/plane_master/game_world/PM = locate(/obj/screen/plane_master/game_world) in parent.screen
PM.filters -= AMBIENT_OCCLUSION
if(ambientocclusion)
PM.filters += AMBIENT_OCCLUSION
if("save")
save_preferences()
save_character()
@@ -1642,4 +1648,4 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(icon_updates)
character.update_body()
character.update_hair()
character.update_body_parts()
character.update_body_parts()
+17 -14
View File
@@ -130,6 +130,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["uses_glasses_colour"]>> uses_glasses_colour
S["clientfps"] >> clientfps
S["parallax"] >> parallax
S["ambientocclusion"] >> ambientocclusion
S["menuoptions"] >> menuoptions
S["enable_tips"] >> enable_tips
S["tip_delay"] >> tip_delay
@@ -160,6 +161,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
toggles = sanitize_integer(toggles, 0, 65535, initial(toggles))
clientfps = sanitize_integer(clientfps, 0, 1000, 0)
parallax = sanitize_integer(parallax, PARALLAX_INSANE, PARALLAX_DISABLE, null)
ambientocclusion = sanitize_integer(ambientocclusion, 0, 1, initial(ambientocclusion))
ghost_form = sanitize_inlist(ghost_form, GLOB.ghost_forms, initial(ghost_form))
ghost_orbit = sanitize_inlist(ghost_orbit, GLOB.ghost_orbits, initial(ghost_orbit))
ghost_accs = sanitize_inlist(ghost_accs, GLOB.ghost_accs_options, GHOST_ACCS_DEFAULT_OPTION)
@@ -210,6 +212,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["uses_glasses_colour"], uses_glasses_colour)
WRITE_FILE(S["clientfps"], clientfps)
WRITE_FILE(S["parallax"], parallax)
WRITE_FILE(S["ambientocclusion"], ambientocclusion)
WRITE_FILE(S["menuoptions"], menuoptions)
WRITE_FILE(S["enable_tips"], enable_tips)
WRITE_FILE(S["tip_delay"], tip_delay)
@@ -310,11 +313,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["job_engsec_med"] >> job_engsec_med
S["job_engsec_low"] >> job_engsec_low
//Traits
S["all_traits"] >> all_traits
S["positive_traits"] >> positive_traits
S["negative_traits"] >> negative_traits
S["neutral_traits"] >> neutral_traits
//Quirks
S["all_quirks"] >> all_quirks
S["positive_quirks"] >> positive_quirks
S["negative_quirks"] >> negative_quirks
S["neutral_quirks"] >> neutral_quirks
//Citadel code
S["feature_genitals_use_skintone"] >> features["genitals_use_skintone"]
@@ -421,10 +424,10 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
job_engsec_med = sanitize_integer(job_engsec_med, 0, 65535, initial(job_engsec_med))
job_engsec_low = sanitize_integer(job_engsec_low, 0, 65535, initial(job_engsec_low))
all_traits = SANITIZE_LIST(all_traits)
positive_traits = SANITIZE_LIST(positive_traits)
negative_traits = SANITIZE_LIST(negative_traits)
neutral_traits = SANITIZE_LIST(neutral_traits)
all_quirks = SANITIZE_LIST(all_quirks)
positive_quirks = SANITIZE_LIST(positive_quirks)
negative_quirks = SANITIZE_LIST(negative_quirks)
neutral_quirks = SANITIZE_LIST(neutral_quirks)
cit_character_pref_load(S)
@@ -491,11 +494,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["job_engsec_med"] , job_engsec_med)
WRITE_FILE(S["job_engsec_low"] , job_engsec_low)
//Traits
WRITE_FILE(S["all_traits"] , all_traits)
WRITE_FILE(S["positive_traits"] , positive_traits)
WRITE_FILE(S["negative_traits"] , negative_traits)
WRITE_FILE(S["neutral_traits"] , neutral_traits)
//Quirks
WRITE_FILE(S["all_quirks"] , all_quirks)
WRITE_FILE(S["positive_quirks"] , positive_quirks)
WRITE_FILE(S["negative_quirks"] , negative_quirks)
WRITE_FILE(S["neutral_quirks"] , neutral_quirks)
cit_character_pref_save(S)
+8 -6
View File
@@ -81,12 +81,14 @@
/obj/item/clothing/equipped(mob/user, slot)
..()
if (!istype(user))
return
if(slot_flags & slotdefine2slotbit(slot)) //Was equipped to a valid slot for this item?
for(var/variable in user_vars_to_edit)
if(variable in user.vars)
user_vars_remembered[variable] = user.vars[variable]
user.vars[variable] = user_vars_to_edit[variable]
if (LAZYLEN(user_vars_to_edit))
for(var/variable in user_vars_to_edit)
if(variable in user.vars)
LAZYSET(user_vars_remembered, variable, user.vars[variable])
user.vv_edit_var(variable, user_vars_to_edit[variable])
/obj/item/clothing/examine(mob/user)
..()
@@ -285,4 +287,4 @@ BLIND // can't see anything
Shreds.desc = "The sad remains of what used to be [name]."
deconstruct(FALSE)
else
..()
..()
@@ -365,6 +365,7 @@
scan_reagents = 1
flags_1 = NODROP_1
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
resistance_flags = LAVA_PROOF | FIRE_PROOF
/obj/item/clothing/glasses/godeye/attackby(obj/item/W as obj, mob/user as mob, params)
if(istype(W, src) && W != src && W.loc == user)
@@ -93,7 +93,7 @@
MA.alpha = 180
MA.maptext = "[strength]k"
MA.color = "#64C864"
MA.layer = AREA_LAYER
MA.layer = FLY_LAYER
pic.appearance = MA
flick_overlay(pic, list(user.client), 8)
+8
View File
@@ -158,12 +158,20 @@
strip_delay = 100
dog_fashion = null
/obj/item/clothing/head/helmet/roman/fake
desc = "An ancient helmet made of plastic and leather."
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
/obj/item/clothing/head/helmet/roman/legionaire
name = "roman legionaire helmet"
desc = "An ancient helmet made of bronze and leather. Has a red crest on top of it."
icon_state = "roman_c"
item_state = "roman_c"
/obj/item/clothing/head/helmet/roman/legionaire/fake
desc = "An ancient helmet made of plastic and leather. Has a red crest on top of it."
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
/obj/item/clothing/head/helmet/gladiator
name = "gladiator helmet"
desc = "Ave, Imperator, morituri te salutant."
+24 -1
View File
@@ -321,4 +321,27 @@
name = "headress of Nemes"
desc = "Lavish space tomb not included."
icon_state = "nemes_headdress"
icon_state = "nemes_headdress"
icon_state = "nemes_headdress"
/obj/item/clothing/head/frenchberet
name = "french beret"
desc = "A quality beret, infused with the aroma of chain-smoking, wine-swilling Parisians. You feel less inclined to engage military conflict, for some reason."
icon_state = "beretblack"
/obj/item/clothing/head/frenchberet/speechModification(M)
if(copytext(M, 1, 2) != "*")
M = " [M]"
var/list/french_words = strings("french_replacement.json", "french")
for(var/key in french_words)
var/value = french_words[key]
if(islist(value))
value = pick(value)
M = replacetextEx(M, " [uppertext(key)]", " [uppertext(value)]")
M = replacetextEx(M, " [capitalize(key)]", " [capitalize(value)]")
M = replacetextEx(M, " [key]", " [value]")
if(prob(3))
M += pick(" Honh honh honh!"," Honh!"," Zut Alors!")
return trim(M)
+1 -1
View File
@@ -47,7 +47,7 @@
/obj/item/clothing/mask/fakemoustache/italian/speechModification(M)
if(copytext(M, 1, 2) != "*")
M = " [M]"
var/list/italian_words = strings("word_replacement.json", "italian")
var/list/italian_words = strings("italian_replacement.json", "italian")
for(var/key in italian_words)
var/value = italian_words[key]
+10 -1
View File
@@ -126,7 +126,7 @@
if(user.transferItemToLoc(I, src))
jetpack = I
to_chat(user, "<span class='notice'>You successfully install the jetpack into [src].</span>")
return
else if(istype(I, /obj/item/screwdriver))
if(!jetpack)
to_chat(user, "<span class='warning'>[src] has no jetpack installed.</span>")
@@ -139,6 +139,8 @@
jetpack.forceMove(drop_location())
jetpack = null
to_chat(user, "<span class='notice'>You successfully remove the jetpack from [src].</span>")
return
return ..()
/obj/item/clothing/suit/space/hardsuit/equipped(mob/user, slot)
@@ -237,6 +239,9 @@
brightness_on = 7
allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/resonator, /obj/item/mining_scanner, /obj/item/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator)
/obj/item/clothing/head/helmet/space/hardsuit/mining/Initialize()
. = ..()
AddComponent(/datum/component/armor_plate)
/obj/item/clothing/suit/space/hardsuit/mining
icon_state = "hardsuit-mining"
@@ -250,6 +255,10 @@
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/mining
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
/obj/item/clothing/suit/space/hardsuit/mining/Initialize()
. = ..()
AddComponent(/datum/component/armor_plate)
//Syndicate hardsuit
/obj/item/clothing/head/helmet/space/hardsuit/syndi
name = "blood-red hardsuit helmet"
-180
View File
@@ -165,186 +165,6 @@
. = ..()
allowed = GLOB.detective_vest_allowed
//Reactive armor
/obj/item/clothing/suit/armor/reactive
name = "reactive armor"
desc = "Doesn't seem to do much for some reason."
var/active = 0
var/reactivearmor_cooldown_duration = 0 //cooldown specific to reactive armor
var/reactivearmor_cooldown = 0
icon_state = "reactiveoff"
item_state = "reactiveoff"
blood_overlay_type = "armor"
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
actions_types = list(/datum/action/item_action/toggle)
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
hit_reaction_chance = 50
/obj/item/clothing/suit/armor/reactive/attack_self(mob/user)
src.active = !( src.active )
if (src.active)
to_chat(user, "<span class='notice'>[src] is now active.</span>")
src.icon_state = "reactive"
src.item_state = "reactive"
else
to_chat(user, "<span class='notice'>[src] is now inactive.</span>")
src.icon_state = "reactiveoff"
src.item_state = "reactiveoff"
src.add_fingerprint(user)
return
/obj/item/clothing/suit/armor/reactive/emp_act(severity)
active = 0
src.icon_state = "reactiveoff"
src.item_state = "reactiveoff"
reactivearmor_cooldown = world.time + 200
..()
//When the wearer gets hit, this armor will teleport the user a short distance away (to safety or to more danger, no one knows. That's the fun of it!)
/obj/item/clothing/suit/armor/reactive/teleport
name = "reactive teleport armor"
desc = "Someone separated our Research Director from his own head!"
var/tele_range = 6
var/rad_amount= 15
reactivearmor_cooldown_duration = 100
/obj/item/clothing/suit/armor/reactive/teleport/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(!active)
return 0
if(prob(hit_reaction_chance))
var/mob/living/carbon/human/H = owner
if(world.time < reactivearmor_cooldown)
owner.visible_message("<span class='danger'>The reactive teleport system is still recharging! It fails to teleport [H]!</span>")
return
owner.visible_message("<span class='danger'>The reactive teleport system flings [H] clear of [attack_text], shutting itself off in the process!</span>")
var/list/turfs = new/list()
for(var/turf/T in orange(tele_range, H))
if(T.density)
continue
if(T.x>world.maxx-tele_range || T.x<tele_range)
continue
if(T.y>world.maxy-tele_range || T.y<tele_range)
continue
turfs += T
if(!turfs.len)
turfs += pick(/turf in orange(tele_range, H))
var/turf/picked = pick(turfs)
if(!isturf(picked))
return
H.forceMove(picked)
H.rad_act(rad_amount)
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
return 1
return 0
/obj/item/clothing/suit/armor/reactive/fire
name = "reactive incendiary armor"
desc = "An experimental suit of armor with a reactive sensor array rigged to a flame emitter. For the stylish pyromaniac."
/obj/item/clothing/suit/armor/reactive/fire/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(!active)
return 0
if(prob(hit_reaction_chance))
if(world.time < reactivearmor_cooldown)
owner.visible_message("<span class='danger'>The reactive incendiary armor on [owner] activates, but fails to send out flames as it is still recharging its flame jets!</span>")
return
owner.visible_message("<span class='danger'>[src] blocks [attack_text], sending out jets of flame!</span>")
for(var/mob/living/carbon/C in range(6, owner))
if(C != owner)
C.fire_stacks += 8
C.IgniteMob()
owner.fire_stacks = -20
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
return 1
return 0
/obj/item/clothing/suit/armor/reactive/stealth
name = "reactive stealth armor"
desc = "An experimental suit of armor that renders the wearer invisible on detection of imminent harm, and creates a decoy that runs away from the owner. You can't fight what you can't see."
/obj/item/clothing/suit/armor/reactive/stealth/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(!active)
return 0
if(prob(hit_reaction_chance))
if(world.time < reactivearmor_cooldown)
owner.visible_message("<span class='danger'>The reactive stealth system on [owner] activates, but is still recharging its holographic emitters!</span>")
return
var/mob/living/simple_animal/hostile/illusion/escape/E = new(owner.loc)
E.Copy_Parent(owner, 50)
E.GiveTarget(owner) //so it starts running right away
E.Goto(owner, E.move_to_delay, E.minimum_distance)
owner.alpha = 0
owner.visible_message("<span class='danger'>[owner] is hit by [attack_text] in the chest!</span>") //We pretend to be hit, since blocking it would stop the message otherwise
spawn(40)
owner.alpha = initial(owner.alpha)
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
return 1
/obj/item/clothing/suit/armor/reactive/tesla
name = "reactive tesla armor"
desc = "An experimental suit of armor with sensitive detectors hooked up to a huge capacitor grid, with emitters strutting out of it. Zap."
siemens_coefficient = -1
var/tesla_power = 25000
var/tesla_range = 20
var/tesla_boom = FALSE
var/tesla_stun = FALSE
/obj/item/clothing/suit/armor/reactive/tesla/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(!active)
return 0
if(prob(hit_reaction_chance))
if(world.time < reactivearmor_cooldown)
var/datum/effect_system/spark_spread/sparks = new /datum/effect_system/spark_spread
sparks.set_up(1, 1, src)
sparks.start()
owner.visible_message("<span class='danger'>The tesla capacitors on [owner]'s reactive tesla armor are still recharging! The armor merely emits some sparks.</span>")
return
owner.visible_message("<span class='danger'>[src] blocks [attack_text], sending out arcs of lightning!</span>")
tesla_zap(owner,tesla_range,tesla_power,tesla_boom, tesla_stun)
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
return 1
/obj/item/clothing/suit/armor/reactive/table
name = "reactive table armor"
desc = "If you can't beat the memes, embrace them."
var/tele_range = 10
/obj/item/clothing/suit/armor/reactive/table/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(!active)
return 0
if(prob(hit_reaction_chance))
var/mob/living/carbon/human/H = owner
if(world.time < reactivearmor_cooldown)
owner.visible_message("<span class='danger'>The reactive table armor's fabricators are still on cooldown!</span>")
return
owner.visible_message("<span class='danger'>The reactive teleport system flings [H] clear of [attack_text] and slams them into a fabricated table!</span>")
owner.visible_message("<font color='red' size='3'>[H] GOES ON THE TABLE!!!</font>")
owner.Knockdown(40)
var/list/turfs = new/list()
for(var/turf/T in orange(tele_range, H))
if(T.density)
continue
if(T.x>world.maxx-tele_range || T.x<tele_range)
continue
if(T.y>world.maxy-tele_range || T.y<tele_range)
continue
turfs += T
if(!turfs.len)
turfs += pick(/turf in orange(tele_range, H))
var/turf/picked = pick(turfs)
if(!isturf(picked))
return
H.forceMove(picked)
new /obj/structure/table(get_turf(owner))
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
return 1
return 0
/obj/item/clothing/suit/armor/reactive/table/emp_act()
return
//All of the armor below is mostly unused
/obj/item/clothing/suit/armor/centcom
@@ -0,0 +1,235 @@
/obj/item/reactive_armour_shell
name = "reactive armour shell"
desc = "An experimental suit of armour, awaiting installation of an anomaly core."
icon_state = "reactiveoff"
icon = 'icons/obj/clothing/suits.dmi'
w_class = WEIGHT_CLASS_BULKY
/obj/item/reactive_armour_shell/attackby(obj/item/I, mob/user, params)
..()
var/static/list/anomaly_armour_types = list(
/obj/effect/anomaly/grav = /obj/item/clothing/suit/armor/reactive/repulse,
/obj/effect/anomaly/flux = /obj/item/clothing/suit/armor/reactive/tesla,
/obj/effect/anomaly/bluespace = /obj/item/clothing/suit/armor/reactive/teleport,
/obj/effect/anomaly/pyro = /obj/item/clothing/suit/armor/reactive/fire)
if(istype(I, /obj/item/assembly/signaler/anomaly))
var/obj/item/assembly/signaler/anomaly/A = I
var/armour_path = anomaly_armour_types[A.anomaly_type]
if(!armour_path)
armour_path = /obj/item/clothing/suit/armor/reactive/stealth //Lets not cheat the player if an anomaly type doesnt have its own armour coded
to_chat(user, "You insert [A] into the chest plate, and the armour gently hums to life.")
new armour_path(get_turf(src))
qdel(src)
qdel(A)
//Reactive armor
/obj/item/clothing/suit/armor/reactive
name = "reactive armor"
desc = "Doesn't seem to do much for some reason."
var/active = 0
var/reactivearmor_cooldown_duration = 0 //cooldown specific to reactive armor
var/reactivearmor_cooldown = 0
icon_state = "reactiveoff"
item_state = "reactiveoff"
blood_overlay_type = "armor"
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
actions_types = list(/datum/action/item_action/toggle)
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
hit_reaction_chance = 50
/obj/item/clothing/suit/armor/reactive/attack_self(mob/user)
active = !(active)
if(active)
to_chat(user, "<span class='notice'>[src] is now active.</span>")
icon_state = "reactive"
item_state = "reactive"
else
to_chat(user, "<span class='notice'>[src] is now inactive.</span>")
icon_state = "reactiveoff"
item_state = "reactiveoff"
add_fingerprint(user)
return
/obj/item/clothing/suit/armor/reactive/emp_act(severity)
active = 0
icon_state = "reactiveoff"
item_state = "reactiveoff"
reactivearmor_cooldown = world.time + 200
..()
//When the wearer gets hit, this armor will teleport the user a short distance away (to safety or to more danger, no one knows. That's the fun of it!)
/obj/item/clothing/suit/armor/reactive/teleport
name = "reactive teleport armor"
desc = "Someone separated our Research Director from his own head!"
var/tele_range = 6
var/rad_amount= 15
reactivearmor_cooldown_duration = 100
/obj/item/clothing/suit/armor/reactive/teleport/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(!active)
return 0
if(prob(hit_reaction_chance))
var/mob/living/carbon/human/H = owner
if(world.time < reactivearmor_cooldown)
owner.visible_message("<span class='danger'>The reactive teleport system is still recharging! It fails to teleport [H]!</span>")
return
owner.visible_message("<span class='danger'>The reactive teleport system flings [H] clear of [attack_text], shutting itself off in the process!</span>")
var/list/turfs = new/list()
for(var/turf/T in orange(tele_range, H))
if(T.density)
continue
if(T.x>world.maxx-tele_range || T.x<tele_range)
continue
if(T.y>world.maxy-tele_range || T.y<tele_range)
continue
turfs += T
if(!turfs.len)
turfs += pick(/turf in orange(tele_range, H))
var/turf/picked = pick(turfs)
if(!isturf(picked))
return
H.forceMove(picked)
H.rad_act(rad_amount)
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
return 1
return 0
//Fire
/obj/item/clothing/suit/armor/reactive/fire
name = "reactive incendiary armor"
desc = "An experimental suit of armor with a reactive sensor array rigged to a flame emitter. For the stylish pyromaniac."
/obj/item/clothing/suit/armor/reactive/fire/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(!active)
return 0
if(prob(hit_reaction_chance))
if(world.time < reactivearmor_cooldown)
owner.visible_message("<span class='danger'>The reactive incendiary armor on [owner] activates, but fails to send out flames as it is still recharging its flame jets!</span>")
return
owner.visible_message("<span class='danger'>[src] blocks [attack_text], sending out jets of flame!</span>")
for(var/mob/living/carbon/C in range(6, owner))
if(C != owner)
C.fire_stacks += 8
C.IgniteMob()
owner.fire_stacks = -20
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
return 1
return 0
//Stealth
/obj/item/clothing/suit/armor/reactive/stealth
name = "reactive stealth armor"
desc = "An experimental suit of armor that renders the wearer invisible on detection of imminent harm, and creates a decoy that runs away from the owner. You can't fight what you can't see."
/obj/item/clothing/suit/armor/reactive/stealth/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(!active)
return 0
if(prob(hit_reaction_chance))
if(world.time < reactivearmor_cooldown)
owner.visible_message("<span class='danger'>The reactive stealth system on [owner] activates, but is still recharging its holographic emitters!</span>")
return
var/mob/living/simple_animal/hostile/illusion/escape/E = new(owner.loc)
E.Copy_Parent(owner, 50)
E.GiveTarget(owner) //so it starts running right away
E.Goto(owner, E.move_to_delay, E.minimum_distance)
owner.alpha = 0
owner.visible_message("<span class='danger'>[owner] is hit by [attack_text] in the chest!</span>") //We pretend to be hit, since blocking it would stop the message otherwise
spawn(40)
owner.alpha = initial(owner.alpha)
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
return 1
//Tesla
/obj/item/clothing/suit/armor/reactive/tesla
name = "reactive tesla armor"
desc = "An experimental suit of armor with sensitive detectors hooked up to a huge capacitor grid, with emitters strutting out of it. Zap."
siemens_coefficient = -1
var/tesla_power = 25000
var/tesla_range = 20
var/tesla_boom = FALSE
var/tesla_stun = FALSE
/obj/item/clothing/suit/armor/reactive/tesla/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(!active)
return 0
if(prob(hit_reaction_chance))
if(world.time < reactivearmor_cooldown)
var/datum/effect_system/spark_spread/sparks = new /datum/effect_system/spark_spread
sparks.set_up(1, 1, src)
sparks.start()
owner.visible_message("<span class='danger'>The tesla capacitors on [owner]'s reactive tesla armor are still recharging! The armor merely emits some sparks.</span>")
return
owner.visible_message("<span class='danger'>[src] blocks [attack_text], sending out arcs of lightning!</span>")
tesla_zap(owner,tesla_range,tesla_power,tesla_boom, tesla_stun)
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
return 1
//Repulse
/obj/item/clothing/suit/armor/reactive/repulse
name = "reactive repulse armor"
desc = "An experimental suit of armor that violently throws back attackers."
/obj/item/clothing/suit/armor/reactive/repulse/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(!active)
return 0
if(prob(hit_reaction_chance))
if(world.time < reactivearmor_cooldown)
owner.visible_message("<span class='danger'>The repulse generator is still recharging!</span>")
return 0
owner.visible_message("<span class='danger'>[src] blocks [attack_text], converting the attack into a wave of force!</span>")
var/turf/T = get_turf(owner)
var/list/thrown_items = list()
for(var/atom/movable/A in range(T, 7))
if(A == owner || A.anchored || thrown_items[A])
continue
var/throwtarget = get_edge_target_turf(src, get_dir(src, get_step_away(A, src)))
A.throw_at(throwtarget,10,1)
thrown_items[A] = A
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
return 1
/obj/item/clothing/suit/armor/reactive/table
name = "reactive table armor"
desc = "If you can't beat the memes, embrace them."
var/tele_range = 10
/obj/item/clothing/suit/armor/reactive/table/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(!active)
return 0
if(prob(hit_reaction_chance))
var/mob/living/carbon/human/H = owner
if(world.time < reactivearmor_cooldown)
owner.visible_message("<span class='danger'>The reactive table armor's fabricators are still on cooldown!</span>")
return
owner.visible_message("<span class='danger'>The reactive teleport system flings [H] clear of [attack_text] and slams them into a fabricated table!</span>")
owner.visible_message("<font color='red' size='3'>[H] GOES ON THE TABLE!!!</font>")
owner.Knockdown(40)
var/list/turfs = new/list()
for(var/turf/T in orange(tele_range, H))
if(T.density)
continue
if(T.x>world.maxx-tele_range || T.x<tele_range)
continue
if(T.y>world.maxy-tele_range || T.y<tele_range)
continue
turfs += T
if(!turfs.len)
turfs += pick(/turf in orange(tele_range, H))
var/turf/picked = pick(turfs)
if(!isturf(picked))
return
H.forceMove(picked)
new /obj/structure/table(get_turf(owner))
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
return 1
return 0
/obj/item/clothing/suit/armor/reactive/table/emp_act()
return
@@ -28,6 +28,14 @@
item_state = "gy_suit"
item_color = "security"
/obj/item/clothing/under/rank/security/skirt
name = "security jumpskirt"
desc = "A \"tactical\" security jumpsuit with the legs replaced by a skirt."
icon_state = "secskirt"
item_state = "r_suit"
item_color = "secskirt"
can_adjust = FALSE //you know now that i think of it if you adjust the skirt and the sprite disappears isn't that just like flashing everyone
/obj/item/clothing/under/rank/warden
name = "security suit"
+4 -2
View File
@@ -15,8 +15,10 @@
search = findtext(text, ":", pos+1)
if(search)
emoji = lowertext(copytext(text, pos+1, search))
if(emoji in emojis)
parsed += icon2html('icons/emoji.dmi', world, emoji)
var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/goonchat)
var/tag = sheet.icon_tag("emoji-[emoji]")
if(tag)
parsed += tag
pos = search + 1
else
parsed += copytext(text, pos, search)
@@ -344,6 +344,15 @@
list_reagents = list("limejuice" = 100)
foodtype = FRUIT
/obj/item/reagent_containers/food/drinks/bottle/menthol
name = "menthol"
desc = "Tastes naturally minty, and imparts a very mild numbing sensation."
icon_state = "mentholbox"
item_state = "carton"
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi'
isGlass = FALSE
list_reagents = list("menthol" = 100)
////////////////////////// MOLOTOV ///////////////////////
/obj/item/reagent_containers/food/drinks/bottle/molotov
@@ -158,7 +158,7 @@
desc = "A timeless classic."
ingredients_placement = INGREDIENTS_STACKPLUSTOP
icon = 'icons/obj/food/burgerbread.dmi'
icon_state = "bun"
icon_state = "custburg"
foodtype = GRAIN
@@ -299,8 +299,7 @@
qdel(S)
return TRUE
for(var/obj/item/stack/sheet/wetleather/WL in src)
var/obj/item/stack/sheet/leather/L = new(drop_location())
L.amount = WL.amount
new /obj/item/stack/sheet/leather(drop_location(), WL.amount)
qdel(WL)
return TRUE
return FALSE
@@ -623,4 +623,42 @@
id = "crevice_spike"
results = list("crevice_spike" = 6)
required_reagents = list("limejuice" = 2, "capsaicin" = 4) //2 powdered delta (sour), 4 flanergide (spicy)
mix_message = "The mixture stings your eyes as it settles."
mix_message = "The mixture stings your eyes as it settles."
/datum/chemical_reaction/sake
name = "sake"
id = "sake"
results = list("sake" = 10)
required_reagents = list("rice" = 10)
required_catalysts = list("enzyme" = 5)
mix_message = "The rice grains ferment into a clear, sweet-smelling liquid."
/datum/chemical_reaction/alexander
name = "Alexander"
id = "alexander"
results = list("alexander" = 3)
required_reagents = list("cognac" = 1, "creme_de_cacao" = 1, "cream" = 1)
/datum/chemical_reaction/sidecar
name = "Sidecar"
id = "sidecar"
results = list("sidecar" = 4)
required_reagents = list("cognac" = 2, "triple_sec" = 1, "lemonjuice" = 1)
/datum/chemical_reaction/between_the_sheets
name = "Between the Sheets"
id = "between_the_sheets"
results = list("between_the_sheets" = 5)
required_reagents = list("rum" = 1, "sidecar" = 4)
/datum/chemical_reaction/kamikaze
name = "Kamikaze"
id = "kamikaze"
results = list("kamikaze" = 3)
required_reagents = list("vodka" = 1, "triple_sec" = 1, "limejuice" = 1)
/datum/chemical_reaction/mojito
name = "Mojito"
id = "mojito"
results = list("mojito" = 5)
required_reagents = list("rum" = 1, "sugar" = 1, "limejuice" = 1, "sodawater" = 1, "menthol" = 1)
+1 -2
View File
@@ -46,8 +46,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("data/iconCache.sav")) //Cache of ic
if(!owner)
return
var/datum/asset/stuff = get_asset_datum(/datum/asset/simple/goonchat)
stuff.register()
var/datum/asset/stuff = get_asset_datum(/datum/asset/group/goonchat)
stuff.send(owner)
owner << browse(file('code/modules/goonchat/browserassets/html/browserOutput.html'), "window=browseroutput")
@@ -6,6 +6,7 @@
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" href="font-awesome.css" />
<link rel="stylesheet" type="text/css" href="browserOutput.css" />
<link rel="stylesheet" type="text/css" href="spritesheet_chat.css" />
<script type="text/javascript" src="errorHandler.js"></script>
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="json2.min.js"></script>
+9 -1
View File
@@ -70,6 +70,7 @@
begin_month = DECEMBER
end_day = 2
end_month = JANUARY
drone_hat = /obj/item/clothing/head/festive
/datum/holiday/new_year/getStationPrefix()
return pick("Party","New","Hangover","Resolution")
@@ -78,6 +79,7 @@
name = "Groundhog Day"
begin_day = 2
begin_month = FEBRUARY
drone_hat = /obj/item/clothing/head/helmet/space/chronos
/datum/holiday/valentines
name = VALENTINES
@@ -92,6 +94,7 @@
name = "Birthday of Space Station 13"
begin_day = 16
begin_month = FEBRUARY
drone_hat = /obj/item/clothing/head/festive
/datum/holiday/birthday/greet()
var/game_age = text2num(time2text(world.timeofday, "YY")) - 3
@@ -202,6 +205,7 @@
name = "UFO Day"
begin_day = 2
begin_month = JULY
drone_hat = /obj/item/clothing/mask/facehugger/dead
/datum/holiday/UFO/getStationPrefix() //Is such a thing even possible?
return pick("Ayy","Truth","Tsoukalos","Mulder") //Yes it is!
@@ -272,11 +276,13 @@
name = "Smiling Day"
begin_day = 7
begin_month = OCTOBER
drone_hat = /obj/item/clothing/head/papersack/smiley
/datum/holiday/boss
name = "Boss' Day"
begin_day = 16
begin_month = OCTOBER
drone_hat = /obj/item/clothing/head/that
/datum/holiday/halloween
name = HALLOWEEN
@@ -305,6 +311,7 @@
name = "Flowers Day"
begin_day = 19
begin_month = NOVEMBER
drone_hat = /obj/item/reagent_containers/food/snacks/grown/moonflower
/datum/holiday/hello
name = "Saying-'Hello' Day"
@@ -312,7 +319,7 @@
begin_month = NOVEMBER
/datum/holiday/hello/greet()
return "[pick(list("Aloha", "Bonjour", "Hello", "Hi", "Greetings", "Salutations", "Bienvenidos", "Hola", "Howdy"))]! " + ..()
return "[pick(list("Aloha", "Bonjour", "Hello", "Hi", "Greetings", "Salutations", "Bienvenidos", "Hola", "Howdy", "Ni hao", "Guten Tag", "Konnichiwa", "G'day cunt"))]! " + ..()
/datum/holiday/human_rights
name = "Human-Rights Day"
@@ -323,6 +330,7 @@
name = "Monkey Day"
begin_day = 14
begin_month = DECEMBER
drone_hat = /obj/item/clothing/mask/gas/monkeymask
/datum/holiday/thanksgiving
name = "Thanksgiving in the United States"
+1 -2
View File
@@ -262,8 +262,7 @@
if(!check_cost(D.materials, amount))
return FALSE
var/obj/item/stack/product = new D.build_path(loc)
product.amount = amount
new D.build_path(drop_location(), amount)
for(var/R in D.make_reagents)
beaker.reagents.add_reagent(R, D.make_reagents[R]*amount)
else
+26 -20
View File
@@ -85,14 +85,15 @@
interact(user)
return
else if(istype(I, /obj/item/disk/plantgene))
if(disk)
to_chat(user, "<span class='warning'>A data disk is already loaded into the machine!</span>")
else
if(!user.transferItemToLoc(I, src))
return
disk = I
to_chat(user, "<span class='notice'>You add [I] to the machine.</span>")
interact(user)
if (operation)
to_chat(user, "<span class='notice'>Please complete current operation.</span>")
return
eject_disk()
if(!user.transferItemToLoc(I, src))
return
disk = I
to_chat(user, "<span class='notice'>You add [I] to the machine.</span>")
interact(user)
else
..()
@@ -266,18 +267,13 @@
to_chat(usr, "<span class='notice'>You add [I] to the machine.</span>")
update_icon()
else if(href_list["eject_disk"] && !operation)
if (disk)
disk.forceMove(drop_location())
disk.verb_pickup()
disk = null
update_genes()
else
var/obj/item/I = usr.get_active_held_item()
if(istype(I, /obj/item/disk/plantgene))
if(!usr.transferItemToLoc(I, src))
return
disk = I
to_chat(usr, "<span class='notice'>You add [I] to the machine.</span>")
var/obj/item/I = usr.get_active_held_item()
eject_disk()
if(istype(I, /obj/item/disk/plantgene))
if(!usr.transferItemToLoc(I, src))
return
disk = I
to_chat(usr, "<span class='notice'>You add [I] to the machine.</span>")
else if(href_list["op"] == "insert" && disk && disk.gene && seed)
if(!operation) // Wait for confirmation
operation = "insert"
@@ -365,6 +361,16 @@
update_genes()
update_icon()
/obj/machinery/plantgenes/proc/eject_disk()
if (disk && !operation)
if(Adjacent(usr) && !issilicon(usr))
if (!usr.put_in_hands(disk))
disk.forceMove(drop_location())
else
disk.forceMove(drop_location())
disk = null
update_genes()
/obj/machinery/plantgenes/proc/update_genes()
core_genes = list()
reagent_genes = list()
+1 -12
View File
@@ -36,19 +36,8 @@
continue
grassAmt += 1 + round(G.seed.potency * tile_coefficient)
qdel(G)
var/obj/item/stack/tile/GT = new stacktype(user.loc)
while(grassAmt > GT.max_amount)
GT.amount = GT.max_amount
grassAmt -= GT.max_amount
GT = new stacktype(user.loc)
GT.amount = grassAmt
for(var/obj/item/stack/tile/T in user.loc)
if((T.type == stacktype) && (T.amount < T.max_amount))
GT.merge(T)
if(GT.amount <= 0)
break
new stacktype(user.drop_location(), grassAmt)
qdel(src)
return
// Carpet
/obj/item/seeds/grass/carpet
+3 -3
View File
@@ -22,7 +22,7 @@
var/blood_type = null
var/list/features = null
var/factions = null
var/list/traits = null
var/list/quirks = null
var/contains_sample = 0
/obj/item/seeds/replicapod/Initialize()
@@ -42,7 +42,7 @@
blood_type = B.data["blood_type"]
features = B.data["features"]
factions = B.data["factions"]
factions = B.data["traits"]
factions = B.data["quirks"]
contains_sample = TRUE
visible_message("<span class='notice'>The [src] is injected with a fresh blood sample.</span>")
else
@@ -114,7 +114,7 @@
podman.faction |= factions
if(!features["mcolor"])
features["mcolor"] = "#59CE00"
for(var/V in traits)
for(var/V in quirks)
new V(podman)
podman.hardset_dna(null,null,podman.real_name,blood_type, new /datum/species/pod,features)//Discard SE's and UI's, podman cloning is inaccurate, and always make them a podman
podman.set_cloned_appearance()
@@ -142,21 +142,18 @@
/obj/item/integrated_circuit/converter/concatenator
name = "concatenator"
desc = "This joins many strings together to get one big string."
desc = "This can join up to 8 strings together to get one big string."
complexity = 4
inputs = list(
"A" = IC_PINTYPE_STRING,
"B" = IC_PINTYPE_STRING,
"C" = IC_PINTYPE_STRING,
"D" = IC_PINTYPE_STRING,
"E" = IC_PINTYPE_STRING,
"F" = IC_PINTYPE_STRING,
"G" = IC_PINTYPE_STRING,
"H" = IC_PINTYPE_STRING
)
inputs = list()
outputs = list("result" = IC_PINTYPE_STRING)
activators = list("concatenate" = IC_PINTYPE_PULSE_IN, "on concatenated" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
var/number_of_pins = 8
/obj/item/integrated_circuit/converter/concatenator/Initialize()
for(var/i = 1 to number_of_pins)
inputs["input [i]"] = IC_PINTYPE_STRING
. = ..()
/obj/item/integrated_circuit/converter/concatenator/do_work()
var/result = null
@@ -169,6 +166,18 @@
push_data()
activate_pin(2)
/obj/item/integrated_circuit/converter/concatenator/small
name = "small concatenator"
desc = "This can join up to 4 strings together to get one big string."
complexity = 2
number_of_pins = 4
/obj/item/integrated_circuit/converter/concatenator/large
name = "large concatenator"
desc = "This can join up to 16 strings together to get one very big string."
complexity = 6
number_of_pins = 16
/obj/item/integrated_circuit/converter/separator
name = "separator"
desc = "This splits as single string into two at the relative split point."
@@ -203,6 +212,32 @@
activate_pin(2)
/obj/item/integrated_circuit/converter/indexer
name = "indexer"
desc = "This circuit takes a string and an index value, then returns the character found at in the string at the given index."
extended_desc = "Make sure the index is not longer or shorter than the string length. If you don't, the circuit will return empty."
icon_state = "split"
complexity = 4
inputs = list(
"string to index" = IC_PINTYPE_STRING,
"index" = IC_PINTYPE_NUMBER,
)
outputs = list(
"found character" = IC_PINTYPE_STRING
)
activators = list("index" = IC_PINTYPE_PULSE_IN, "on indexed" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/converter/indexer/do_work()
var/strin = get_pin_data(IC_INPUT, 1)
var/ind = get_pin_data(IC_INPUT, 2)
if(ind > 0 && ind <= length(strin))
set_pin_data(IC_OUTPUT, 1, strin[ind])
else
set_pin_data(IC_OUTPUT, 1, "")
push_data()
activate_pin(2)
/obj/item/integrated_circuit/converter/findstring
name = "find text"
desc = "This gives position of sample in the string. Or returns 0."
@@ -216,14 +251,38 @@
outputs = list(
"position" = IC_PINTYPE_NUMBER
)
activators = list("search" = IC_PINTYPE_PULSE_IN, "after search" = IC_PINTYPE_PULSE_OUT)
activators = list("search" = IC_PINTYPE_PULSE_IN, "after search" = IC_PINTYPE_PULSE_OUT, "found" = IC_PINTYPE_PULSE_OUT, "not found" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/converter/findstring/do_work()
var/position = findtext(get_pin_data(IC_INPUT, 1),get_pin_data(IC_INPUT, 2))
set_pin_data(IC_OUTPUT, 1, findtext(get_pin_data(IC_INPUT, 1),get_pin_data(IC_INPUT, 2)) )
set_pin_data(IC_OUTPUT, 1, position)
push_data()
activate_pin(2)
if(position)
activate_pin(3)
else
activate_pin(4)
/obj/item/integrated_circuit/converter/stringlength
name = "get length"
desc = "This circuit will return the number of characters in a string."
complexity = 1
inputs = list(
"string" = IC_PINTYPE_STRING
)
outputs = list(
"length" = IC_PINTYPE_NUMBER
)
activators = list("get length" = IC_PINTYPE_PULSE_IN, "on acquisition" = IC_PINTYPE_PULSE_OUT)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/converter/stringlength/do_work()
set_pin_data(IC_OUTPUT, 1, length(get_pin_data(IC_INPUT, 1)))
push_data()
activate_pin(2)
@@ -232,7 +291,8 @@
name = "string exploder"
desc = "This splits a single string into a list of strings."
extended_desc = "This circuit splits a given string into a list of strings based on the string and given delimiter. \
For example, 'eat this burger' will be converted to list('eat','this','burger')."
For example, 'eat this burger' will be converted to list('eat','this','burger'). Leave the delimiter null to get a list \
of every individual character."
icon_state = "split"
complexity = 4
inputs = list(
@@ -248,7 +308,10 @@
/obj/item/integrated_circuit/converter/exploders/do_work()
var/strin = get_pin_data(IC_INPUT, 1)
var/delimiter = get_pin_data(IC_INPUT, 2)
set_pin_data(IC_OUTPUT, 1, splittext(strin, delimiter))
if(delimiter == null)
set_pin_data(IC_OUTPUT, 1, string2charlist(strin))
else
set_pin_data(IC_OUTPUT, 1, splittext(strin, delimiter))
push_data()
activate_pin(2)
@@ -637,6 +637,7 @@
var/frequency = FREQ_SIGNALER
var/code = DEFAULT_SIGNALER_CODE
var/datum/radio_frequency/radio_connection
var/hearing_range = 1
/obj/item/integrated_circuit/input/signaler/Initialize()
. = ..()
@@ -690,7 +691,11 @@
return 0
activate_pin(3)
audible_message("[icon2html(src, hearers(src))] *beep* *beep*", null, 1)
audible_message("[icon2html(src, hearers(src))] *beep* *beep* *beep*", null, hearing_range)
for(var/CHM in get_hearers_in_view(hearing_range, src))
if(ismob(CHM))
var/mob/LM = CHM
LM.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE)
/obj/item/integrated_circuit/input/ntnet_packet
name = "NTNet networking circuit"
+8 -3
View File
@@ -226,9 +226,14 @@ GLOBAL_PROTECT(exp_to_update)
if(!rolefound)
play_records["Unknown"] += minutes
else
play_records[EXP_TYPE_GHOST] += minutes
if(announce_changes)
to_chat(src,"<span class='notice'>You got: [minutes] Ghost EXP!</span>")
if(holder && !holder.deadmined)
play_records[EXP_TYPE_ADMIN] += minutes
if(announce_changes)
to_chat(src,"<span class='notice'>You got: [minutes] Admin EXP!</span>")
else
play_records[EXP_TYPE_GHOST] += minutes
if(announce_changes)
to_chat(src,"<span class='notice'>You got: [minutes] Ghost EXP!</span>")
else if(isobserver(mob))
play_records[EXP_TYPE_GHOST] += minutes
if(announce_changes)
+1 -1
View File
@@ -91,7 +91,7 @@ Mime
uniform = /obj/item/clothing/under/rank/mime
mask = /obj/item/clothing/mask/gas/mime
gloves = /obj/item/clothing/gloves/color/white
head = /obj/item/clothing/head/beret
head = /obj/item/clothing/head/frenchberet
suit = /obj/item/clothing/suit/suspenders
backpack_contents = list(/obj/item/reagent_containers/food/drinks/bottle/bottleofnothing=1)
+2 -1
View File
@@ -35,7 +35,8 @@
return TRUE
/datum/language/proc/get_icon()
return "[icon2html(icon, world, icon_state)]"
var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/goonchat)
return sheet.icon_tag("language-[icon_state]")
/datum/language/proc/get_random_name(gender, name_count=2, syllable_count=4, syllable_divisor=2)
if(!syllables || !syllables.len)
@@ -25,6 +25,14 @@
armor = list("melee" = 30, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 50, "bio" = 100, "rad" = 50, "fire" = 50, "acid" = 50)
resistance_flags = FIRE_PROOF
/obj/item/clothing/suit/hooded/explorer/Initialize()
. = ..()
AddComponent(/datum/component/armor_plate)
/obj/item/clothing/head/hooded/explorer/Initialize()
. = ..()
AddComponent(/datum/component/armor_plate)
/obj/item/clothing/mask/gas/explorer
name = "explorer gas mask"
desc = "A military-grade gas mask that can be connected to an air supply."
+1 -35
View File
@@ -9,38 +9,4 @@
novariants = FALSE
flags_1 = NOBLUDGEON_1
w_class = WEIGHT_CLASS_NORMAL
layer = MOB_LAYER
var/static/list/goliath_platable_armor_typecache = typecacheof(list(
/obj/item/clothing/head/helmet/space/hardsuit/mining,
/obj/item/clothing/suit/space/hardsuit/mining,
/obj/item/clothing/head/hooded/explorer,
/obj/item/clothing/suit/hooded/explorer))
/obj/item/stack/sheet/animalhide/goliath_hide/afterattack(atom/target, mob/user, proximity_flag)
if(!proximity_flag)
return
if(is_type_in_typecache(target, goliath_platable_armor_typecache))
var/obj/item/clothing/C = target
if(C.armor.melee < 60)
C.armor = C.armor.setRating(melee = min(C.armor.melee + 10, 60))
to_chat(user, "<span class='info'>You strengthen [target], improving its resistance against melee attacks.</span>")
use(1)
else
to_chat(user, "<span class='warning'>You can't improve [C] any further!</span>")
else if(istype(target, /obj/mecha/working/ripley))
var/obj/mecha/working/ripley/D = target
if(D.hides < 3)
D.hides++
D.armor = D.armor.setRating(\
melee = min(D.armor.melee + 10, 70),\
bullet = min(D.armor.bullet + 5, 50),\
laser = min(D.armor.laser + 5, 50))
to_chat(user, "<span class='info'>You strengthen [target], improving its resistance against melee attacks.</span>")
D.update_icon()
if(D.hides == 3)
D.desc = "Autonomous Power Loader Unit. It's wearing a fearsome carapace entirely composed of goliath hide plates - its pilot must be an experienced monster hunter."
else
D.desc = "Autonomous Power Loader Unit. Its armour is enhanced with some goliath hide plates."
use(1)
else
to_chat(user, "<span class='warning'>You can't improve [D] any further!</span>")
layer = MOB_LAYER
+5 -6
View File
@@ -303,13 +303,12 @@
desired = input("How many sheets?", "How many sheets would you like to smelt?", 1) as null|num
var/amount = round(min(desired,50,smelt_amount))
materials.use_amount(alloy.materials, amount)
var/output = new alloy.build_path(src)
if(istype(output, /obj/item/stack/sheet))
var/obj/item/stack/sheet/produced_alloy = output
produced_alloy.amount = amount
unload_mineral(produced_alloy)
var/output
if(ispath(alloy.build_path, /obj/item/stack/sheet))
output = new alloy.build_path(src, amount)
else
unload_mineral(output)
output = new alloy.build_path(src)
unload_mineral(output)
else
to_chat(usr, "<span class='warning'>Required access not found.</span>")
return TRUE
+3 -6
View File
@@ -44,8 +44,7 @@
if(!(text2path(href_list["release"]) in machine.stack_list))
return //someone tried to spawn materials by spoofing hrefs
var/obj/item/stack/sheet/inp = machine.stack_list[text2path(href_list["release"])]
var/obj/item/stack/sheet/out = new inp.type()
out.amount = inp.amount
var/obj/item/stack/sheet/out = new inp.type(null, inp.amount)
inp.amount = 0
machine.unload_mineral(out)
@@ -81,14 +80,12 @@
/obj/machinery/mineral/stacking_machine/proc/process_sheet(obj/item/stack/sheet/inp)
if(!(inp.type in stack_list)) //It's the first of this sheet added
var/obj/item/stack/sheet/s = new inp.type(src,0)
s.amount = 0
var/obj/item/stack/sheet/s = new inp.type(src, 0)
stack_list[inp.type] = s
var/obj/item/stack/sheet/storage = stack_list[inp.type]
storage.amount += inp.amount //Stack the sheets
qdel(inp) //Let the old sheet garbage collect
while(storage.amount > stack_amt) //Get rid of excessive stackage
var/obj/item/stack/sheet/out = new inp.type()
out.amount = stack_amt
var/obj/item/stack/sheet/out = new inp.type(null, stack_amt)
unload_mineral(out)
storage.amount -= stack_amt
@@ -400,7 +400,7 @@
SSticker.mode.make_antag_chance(humanc)
if(humanc && CONFIG_GET(flag/roundstart_traits))
SStraits.AssignTraits(humanc, humanc.client, TRUE)
SSquirks.AssignQuirks(humanc, humanc.client, TRUE)
log_manifest(character.mind.key,character.mind,character,latejoin = TRUE)
@@ -592,6 +592,8 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
var/list/possessible = list()
for(var/mob/living/L in GLOB.alive_mob_list)
if(istype(L,/mob/living/carbon/human/dummy) || !get_turf(L)) //Haha no.
continue
if(!(L in GLOB.player_list) && !L.mind)
possessible += L
+4 -1
View File
@@ -326,7 +326,10 @@
I.plane = initial(I.plane)
I.appearance_flags &= ~NO_CLIENT_COLOR
if(!no_move && !(I.flags_1 & DROPDEL_1)) //item may be moved/qdel'd immedietely, don't bother moving it
I.forceMove(newloc)
if (isnull(newloc))
I.moveToNullspace()
else
I.forceMove(newloc)
I.dropped(src)
return TRUE
+4 -4
View File
@@ -193,10 +193,10 @@
blood_data["real_name"] = real_name
blood_data["features"] = dna.features
blood_data["factions"] = faction
blood_data["traits"] = list()
for(var/V in roundstart_traits)
var/datum/trait/T = V
blood_data["traits"] += T.type
blood_data["quirks"] = list()
for(var/V in roundstart_quirks)
var/datum/quirk/T = V
blood_data["quirks"] += T.type
return blood_data
//get the id of the substance this mob use as blood.
@@ -19,6 +19,7 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy)
//Inefficient pooling/caching way.
GLOBAL_LIST_EMPTY(human_dummy_list)
GLOBAL_LIST_EMPTY(dummy_mob_list)
/proc/generate_or_wait_for_human_dummy(slotkey)
if(!slotkey)
@@ -31,6 +32,7 @@ GLOBAL_LIST_EMPTY(human_dummy_list)
if(QDELETED(D))
D = new
GLOB.human_dummy_list[slotkey] = D
GLOB.dummy_mob_list += D
D.in_use = TRUE
return D
@@ -733,8 +733,8 @@
if(0 to NUTRITION_LEVEL_STARVING)
to_chat(src, "<span class='danger'>You're starving!</span>")
if(roundstart_traits.len)
to_chat(src, "<span class='notice'>You have these traits: [get_trait_string()].</span>")
if(roundstart_quirks.len)
to_chat(src, "<span class='notice'>You have these quirks: [get_trait_string()].</span>")
else
if(wear_suit)
wear_suit.add_fingerprint(M)
+2 -1
View File
@@ -13,7 +13,8 @@
message = T.TongueSpeech(message)
if(wear_mask)
message = wear_mask.speechModification(message)
if(head)
message = head.speechModification(message)
return message
/mob/living/carbon/can_speak_vocal(message)
+13 -10
View File
@@ -407,16 +407,14 @@
*/
//Recursive function to find everything a mob is holding. Really shitty proc tbh.
/mob/living/get_contents()
. = list()
. |= list(src)
for(var/obj/o in .)
var/list/newlist = list()
o.SendSignal(COMSIG_TRY_STORAGE_RETURN_INVENTORY, newlist)
. |= newlist
for(var/obj/item/clothing/under/U in .)
. |= U.contents
for(var/obj/item/folder/F in .)
. |= F.contents
var/list/ret = list()
ret |= contents //add our contents
for(var/i in ret.Copy()) //iterate storage objects
var/atom/A = i
A.SendSignal(COMSIG_TRY_STORAGE_RETURN_INVENTORY, ret)
for(var/obj/item/folder/F in ret.Copy()) //very snowflakey-ly iterate folders
ret |= F.contents
return ret
// Living mobs use can_inject() to make sure that the mob is not syringe-proof in general.
/mob/living/proc/can_inject()
@@ -494,6 +492,11 @@
ExtinguishMob()
fire_stacks = 0
update_canmove()
GET_COMPONENT(mood, /datum/component/mood)
if (mood)
QDEL_LIST(mood.mood_events)
mood.sanity = SANITY_GREAT
mood.update_mood()
//proc called by revive(), to check if we can actually ressuscitate the mob (we don't want to revive him and have him instantly die again)
+1 -2
View File
@@ -317,8 +317,7 @@
return shock_damage
/mob/living/emp_act(severity)
var/list/L = src.get_contents()
for(var/obj/O in L)
for(var/obj/O in contents)
O.emp_act(severity)
..()
+1 -1
View File
@@ -34,7 +34,7 @@
var/list/status_traits = list()
var/list/roundstart_traits = list()
var/list/roundstart_quirks = list()
var/list/surgeries = list() //a list of surgery datums. generally empty, they're added when the player wants them.
@@ -170,7 +170,8 @@
if(href_list["send"])
signaler.send_activation()
audible_message("[icon2html(src, world)] *beep* *beep*")
audible_message("[icon2html(src, hearers(src))] *beep* *beep* *beep*")
playsound(src, 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE)
if(href_list["freq"])
var/new_frequency = (signaler.frequency + text2num(href_list["freq"]))
@@ -831,7 +831,7 @@
set_module = /obj/item/robot_module/janitor
/mob/living/silicon/robot/modules/syndicate
icon_state = "syndie_bloodhound"
icon_state = "synd_sec"
faction = list(ROLE_SYNDICATE)
bubble_icon = "syndibot"
req_access = list(ACCESS_SYNDICATE)
@@ -859,7 +859,7 @@
return
/mob/living/silicon/robot/modules/syndicate/medical
icon_state = "syndi-medi"
icon_state = "synd_medical"
playstyle_string = "<span class='big bold'>You are a Syndicate medical cyborg!</span><br>\
<b>You are armed with powerful medical tools to aid you in your mission: help the operatives secure the nuclear authentication disk. \
Your hypospray will produce Restorative Nanites, a wonder-drug that will heal most types of bodily damages, including clone and brain damage. It also produces morphine for offense. \
@@ -1,7 +1,7 @@
/obj/item/robot_module
name = "Default"
icon = 'icons/obj/module.dmi'
icon_state = "std_module"
icon_state = "std_mod"
w_class = WEIGHT_CLASS_GIGANTIC
item_state = "electronic"
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
@@ -164,12 +164,7 @@
update_controls()
/mob/living/simple_animal/bot/floorbot/proc/empty_tiles()
var/atom/Tsec = drop_location()
while(specialtiles > initial(tiletype.max_amount))
new tiletype(Tsec,initial(tiletype.max_amount))
specialtiles -= initial(tiletype.max_amount)
new tiletype(Tsec,specialtiles)
new tiletype(drop_location(), specialtiles)
specialtiles = 0
tiletype = null
@@ -378,8 +373,7 @@
if(prob(50))
drop_part(robot_arm, Tsec)
var/obj/item/stack/tile/plasteel/T = new (Tsec)
T.amount = 1
new /obj/item/stack/tile/plasteel(Tsec, 1)
do_sparks(3, TRUE, src)
..()
@@ -2,7 +2,7 @@
name = "\improper honkbot"
desc = "A little robot. It looks happy with its bike horn."
icon = 'icons/mob/aibots.dmi'
icon_state = "honkbot"
icon_state = "honkbot1"
density = FALSE
anchored = FALSE
health = 25
@@ -27,6 +27,7 @@
attacktext = "pummels"
attack_sound = 'sound/weapons/punch1.ogg'
dextrous = TRUE
held_items = list(null, null)
possible_a_intents = list(INTENT_HELP, INTENT_GRAB, INTENT_DISARM, INTENT_HARM)
faction = list("jungle")
robust_searching = TRUE
@@ -9,7 +9,7 @@
icon_dead = "Fugu_dead"
icon_gib = "syndicate_gib"
mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
mouse_opacity = MOUSE_OPACITY_OPAQUE
mouse_opacity = MOUSE_OPACITY_ICON
move_to_delay = 5
friendly = "floats near"
speak_emote = list("puffs")
+8 -8
View File
@@ -146,12 +146,12 @@
else
status_traits[trait] |= list(source)
/mob/living/proc/add_trait_datum(trait, spawn_effects) //separate proc due to the way these ones are handled
if(has_trait(trait))
/mob/living/proc/add_quirk(quirk, spawn_effects) //separate proc due to the way these ones are handled
if(has_trait(quirk))
return
if(!SStraits || !SStraits.traits[trait])
if(!SSquirks || !SSquirks.quirks[quirk])
return
var/datum/trait/T = SStraits.traits[trait]
var/datum/quirk/T = SSquirks.quirks[quirk]
new T (src, spawn_effects)
return TRUE
@@ -180,8 +180,8 @@
if(!LAZYLEN(status_traits[trait]))
status_traits -= trait
/mob/living/proc/remove_trait_datum(trait)
var/datum/trait/T = roundstart_traits[trait]
/mob/living/proc/remove_quirk(quirk)
var/datum/quirk/T = roundstart_quirks[quirk]
if(T)
qdel(T)
return TRUE
@@ -201,8 +201,8 @@
else if(LAZYLEN(status_traits[trait]))
return TRUE
/mob/living/proc/has_trait_datum(trait)
return roundstart_traits[trait]
/mob/living/proc/has_quirk(quirk)
return roundstart_quirks[quirk]
/mob/living/proc/remove_all_traits()
status_traits = list()
+1 -1
View File
@@ -70,7 +70,7 @@
message = src.say_quote(message, get_spans())
var/rendered = "<span class='game deadsay'><span class='prefix'>DEAD:</span> <span class='name'>[name]</span>[alt_name] <span class='message'>[message]</span></span>"
log_message("DEAD: [message]", INDIVIDUAL_SAY_LOG)
deadchat_broadcast(rendered, follow_target = src, speaker_key = K)
/mob/proc/check_emote(message)
+5 -2
View File
@@ -66,7 +66,7 @@
..()
to_chat(user, "<span class='notice'>Alt-click to fold it.</span>")
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/paper)
var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/simple/paper)
assets.send(user)
if(in_range(user, src) || isobserver(user))
@@ -300,7 +300,10 @@
if(!in_range(src, user))
return
stamps += "<img src=large_[P.icon_state].png>"
var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/simple/paper)
if (isnull(stamps))
stamps = sheet.css_tag()
stamps += sheet.icon_tag(P.icon_state)
var/mutable_appearance/stampoverlay = mutable_appearance('icons/obj/bureaucracy.dmi', "paper_[P.icon_state]")
stampoverlay.pixel_x = rand(-2, 2)
stampoverlay.pixel_y = rand(-3, 2)
+31 -26
View File
@@ -34,6 +34,10 @@
#define APC_COVER_OPENED 1
#define APC_COVER_REMOVED 2
#define APC_NOT_CHARGING 0
#define APC_CHARGING 1
#define APC_FULLY_CHARGED 2
// the Area Power Controller (APC), formerly Power Distribution Unit (PDU)
// one per area, needs wire connection to power network through a terminal
@@ -66,7 +70,7 @@
var/equipment = 3
var/environ = 3
var/operating = TRUE
var/charging = 0
var/charging = APC_NOT_CHARGING
var/chargemode = 1
var/chargecount = 0
var/locked = TRUE
@@ -291,11 +295,11 @@
// And now, separately for cleanness, the lighting changing
if(update_state & UPSTATE_ALLGOOD)
switch(charging)
if(0)
if(APC_NOT_CHARGING)
light_color = LIGHT_COLOR_RED
if(1)
if(APC_CHARGING)
light_color = LIGHT_COLOR_BLUE
if(2)
if(APC_FULLY_CHARGED)
light_color = LIGHT_COLOR_GREEN
set_light(lon_range)
else if(update_state & UPSTATE_BLUESCREEN)
@@ -339,9 +343,9 @@
if(!charging)
update_overlay |= APC_UPOVERLAY_CHARGEING0
else if(charging == 1)
else if(charging == APC_CHARGING)
update_overlay |= APC_UPOVERLAY_CHARGEING1
else if(charging == 2)
else if(charging == APC_FULLY_CHARGED)
update_overlay |= APC_UPOVERLAY_CHARGEING2
if (!equipment)
@@ -384,15 +388,6 @@
/obj/machinery/power/apc/crowbar_act(mob/user, obj/item/W)
. = TRUE
if (opened)
if(cell)
user.visible_message("[user] removes \the [cell] from [src]!","<span class='notice'>You remove \the [cell].</span>")
var/turf/T = get_turf(user)
cell.forceMove(T)
cell.update_icon()
cell = null
charging = 0
update_icon()
return
if (has_electronics == APC_ELECTRONICS_INSTALLED)
if (terminal)
to_chat(user, "<span class='warning'>Disconnect the wires first!</span>")
@@ -457,8 +452,14 @@
/obj/machinery/power/apc/screwdriver_act(mob/living/user, obj/item/W)
. = TRUE
if(opened)
if (cell)
to_chat(user, "<span class='warning'>Close the APC first!</span>")
if(cell)
user.visible_message("[user] removes \the [cell] from [src]!","<span class='notice'>You remove \the [cell].</span>")
var/turf/T = get_turf(user)
cell.forceMove(T)
cell.update_icon()
cell = null
charging = APC_NOT_CHARGING
update_icon()
return
else
switch (has_electronics)
@@ -745,7 +746,7 @@
user.put_in_hands(cell)
cell.update_icon()
src.cell = null
charging = 0
charging = APC_NOT_CHARGING
src.update_icon()
return
if((stat & MAINT) && !opened) //no board; no interface
@@ -888,7 +889,7 @@
if("charge")
chargemode = !chargemode
if(!chargemode)
charging = 0
charging = APC_NOT_CHARGING
update_icon()
. = TRUE
if("channel")
@@ -1125,10 +1126,10 @@
if((cell.charge/GLOB.CELLRATE + excess) >= lastused_total) // can we draw enough from cell+grid to cover last usage?
cell.charge = min(cell.maxcharge, cell.charge + GLOB.CELLRATE * excess) //recharge with what we can
add_load(excess) // so draw what we can from the grid
charging = 0
charging = APC_NOT_CHARGING
else // not enough power available to run the last tick!
charging = 0
charging = APC_NOT_CHARGING
chargecount = 0
// This turns everything off in the case that there is still a charge left on the battery, just not enough to run the room.
equipment = autoset(equipment, 0)
@@ -1168,7 +1169,7 @@
area.poweralert(1, src)
// now trickle-charge the cell
if(chargemode && charging == 1 && operating)
if(chargemode && charging == APC_CHARGING && operating)
if(excess > 0) // check to make sure we have enough to charge
// Max charge is capped to % per second constant
var/ch = min(excess*GLOB.CELLRATE, cell.maxcharge*GLOB.CHARGELEVEL)
@@ -1176,13 +1177,13 @@
cell.give(ch) // actually recharge the cell
else
charging = 0 // stop charging
charging = APC_NOT_CHARGING // stop charging
chargecount = 0
// show cell as fully charged if so
if(cell.charge >= cell.maxcharge)
cell.charge = cell.maxcharge
charging = 2
charging = APC_FULLY_CHARGED
if(chargemode)
if(!charging)
@@ -1194,7 +1195,7 @@
if(chargecount == 10)
chargecount = 0
charging = 1
charging = APC_CHARGING
else // chargemode off
charging = 0
@@ -1202,7 +1203,7 @@
else // no cell, switch everything off
charging = 0
charging = APC_NOT_CHARGING
chargecount = 0
equipment = autoset(equipment, 0)
lighting = autoset(lighting, 0)
@@ -1358,6 +1359,10 @@
#undef APC_COVER_OPENED
#undef APC_COVER_REMOVED
#undef APC_NOT_CHARGING
#undef APC_CHARGING
#undef APC_FULLY_CHARGED
//update_overlay
#undef APC_UPOVERLAY_CHARGEING0
#undef APC_UPOVERLAY_CHARGEING1
+2 -7
View File
@@ -111,13 +111,8 @@
/obj/machinery/power/port_gen/pacman/DropFuel()
if(sheets)
var/fail_safe = FALSE
while(sheets > 0 && fail_safe < 100)
fail_safe += 1
var/obj/item/stack/sheet/S = new sheet_path(loc)
var/amount = min(sheets, S.max_amount)
S.amount = amount
sheets -= amount
new sheet_path(drop_location(), sheets)
sheets = 0
/obj/machinery/power/port_gen/pacman/UseFuel()
var/needed_sheets = 1 / (time_per_sheet * consumption / power_output)
+4 -4
View File
@@ -191,12 +191,12 @@
// Give back the glass type we were supplied with
/obj/item/solar_assembly/proc/give_glass(device_broken)
var/atom/Tsec = drop_location()
if(device_broken)
new /obj/item/shard(loc)
new /obj/item/shard(loc)
new /obj/item/shard(Tsec)
new /obj/item/shard(Tsec)
else if(glass_type)
var/obj/item/stack/sheet/S = new glass_type(loc)
S.amount = 2
new glass_type(Tsec, 2)
glass_type = null
+3 -3
View File
@@ -62,9 +62,9 @@
if(default_deconstruction_crowbar(W))
return
if(is_wire_tool(W) && panel_open)
/*if(is_wire_tool(W) && panel_open) CITADEL EDIT - They removed the wires because they don't like my cheating
wires.interact(user)
return
return*/
return ..()
@@ -185,4 +185,4 @@
flick("grounding_rodhit", src)
tesla_buckle_check(power)
else
..()
..()
@@ -1,8 +1,8 @@
/obj/item/ammo_box/magazine/m12g
name = "shotgun magazine (12g taser slugs)"
name = "shotgun magazine (12g buckshot slugs)"
desc = "A drum magazine."
icon_state = "m12gs"
ammo_type = /obj/item/ammo_casing/shotgun/stunslug
icon_state = "m12gb"
ammo_type = /obj/item/ammo_casing/shotgun/buckshot
caliber = "shotgun"
max_ammo = 8
@@ -10,14 +10,14 @@
..()
icon_state = "[initial(icon_state)]-[CEILING(ammo_count(0)/8, 1)*8]"
/obj/item/ammo_box/magazine/m12g/buckshot
name = "shotgun magazine (12g buckshot slugs)"
icon_state = "m12gb"
ammo_type = /obj/item/ammo_casing/shotgun/buckshot
/obj/item/ammo_box/magazine/m12g/stun
name = "shotgun magazine (12g taser slugs)"
icon_state = "m12gs"
ammo_type = /obj/item/ammo_casing/shotgun/stunslug
/obj/item/ammo_box/magazine/m12g/slug
name = "shotgun magazine (12g slugs)"
icon_state = "m12gb"
icon_state = "m12gb" //this may need an unique sprite
ammo_type = /obj/item/ammo_casing/shotgun
/obj/item/ammo_box/magazine/m12g/dragon
@@ -40,7 +40,6 @@
to_chat(user, "<span class='warning'>You need a free hand to hold the gun!</span>")
return
update_icon()
gun.forceMove(user)
user.update_inv_back()
else
to_chat(user, "<span class='warning'>You are already holding the gun!</span>")
@@ -436,7 +436,7 @@
/obj/item/projectile/beam/beam_rifle
name = "particle beam"
icon = ""
icon = null
hitsound = 'sound/effects/explosion3.ogg'
damage = 0 //Handled manually.
damage_type = BURN
@@ -4,7 +4,7 @@
/obj/item/projectile/curse_hand
name = "curse hand"
icon_state = "cursehand"
icon_state = "cursehand0"
hitsound = 'sound/effects/curse4.ogg'
layer = LARGE_MOB_LAYER
damage_type = BURN
@@ -19,10 +19,7 @@
/obj/item/projectile/curse_hand/Initialize(mapload)
. = ..()
handedness = prob(50)
update_icon()
/obj/item/projectile/curse_hand/update_icon()
icon_state = "[icon_state][handedness]"
icon_state = "cursehand[handedness]"
/obj/item/projectile/curse_hand/fire(setAngle)
if(starting)
@@ -433,7 +433,8 @@ obj/machinery/chem_dispenser/proc/work_animation()
"orangejuice",
"limejuice",
"tomatojuice",
"lemonjuice"
"lemonjuice",
"menthol"
)
emagged_reagents = list(
"thirteenloko",
@@ -465,7 +466,8 @@ obj/machinery/chem_dispenser/proc/work_animation()
"hcider",
"creme_de_menthe",
"creme_de_cacao",
"triple_sec"
"triple_sec",
"sake"
)
emagged_reagents = list(
"ethanol",
@@ -499,3 +501,17 @@ obj/machinery/chem_dispenser/proc/work_animation()
"ammonia",
"ash",
"diethylamine")
/obj/machinery/chem_dispenser/fullupgrade //fully upgraded stock parts
/obj/machinery/chem_dispenser/fullupgrade/Initialize()
. = ..()
component_parts = list()
component_parts += new /obj/item/circuitboard/machine/chem_dispenser(null)
component_parts += new /obj/item/stock_parts/matter_bin/bluespace(null)
component_parts += new /obj/item/stock_parts/matter_bin/bluespace(null)
component_parts += new /obj/item/stock_parts/capacitor/quadratic(null)
component_parts += new /obj/item/stock_parts/manipulator/femto(null)
component_parts += new /obj/item/stack/sheet/glass(null)
component_parts += new /obj/item/stock_parts/cell/bluespace(null)
RefreshParts()
@@ -0,0 +1,85 @@
/obj/machinery/chem_dispenser/chem_synthesizer //formerly SCP-294 made by mrty, but now only for testing purposes
name = "\improper debug chemical synthesizer"
desc = "If you see this, yell at adminbus."
icon = 'icons/obj/chemical.dmi'
icon_state = "dispenser"
amount = 10
resistance_flags = INDESTRUCTIBLE | FIRE_PROOF | ACID_PROOF | LAVA_PROOF
working_state = null
nopower_state = null
flags_1 = NODECONSTRUCT_1
var/static/list/shortcuts = list(
"meth" = "methamphetamine",
"tricord" = "tricordrazine"
)
var/mutable_appearance/top_overlay
/obj/machinery/chem_dispenser/chem_synthesizer/Initialize()
. = ..()
GLOB.poi_list += src
top_overlay = mutable_appearance(icon, "disp_beaker", layer = ABOVE_ALL_MOB_LAYER)
update_icon()
/obj/machinery/chem_dispenser/chem_synthesizer/update_icon()
cut_overlays()
add_overlay(top_overlay)
/obj/machinery/chem_dispenser/chem_synthesizer/Destroy()
. = ..()
GLOB.poi_list -= src
QDEL_NULL(top_overlay)
/obj/machinery/chem_dispenser/chem_synthesizer/display_beaker()
return
/obj/machinery/chem_dispenser/chem_synthesizer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "chem_synthesizer", name, 390, 315, master_ui, state)
ui.open()
/obj/machinery/chem_dispenser/chem_synthesizer/ui_act(action, params)
if(..())
return
update_icon()
switch(action)
if("ejectBeaker")
if(beaker)
beaker.forceMove(drop_location())
if(Adjacent(usr) && !issilicon(usr))
usr.put_in_hands(beaker)
beaker = null
. = TRUE
if("input")
var/input_reagent = replacetext(lowertext(input("Enter the name of any liquid", "Input") as text), " ", "") //95% of the time, the reagent id is a lowercase/no spaces version of the name
if(shortcuts[input_reagent])
input_reagent = shortcuts[input_reagent]
else
input_reagent = find_reagent(input_reagent)
if(!input_reagent || !GLOB.chemical_reagents_list[input_reagent])
say("OUT OF RANGE")
return
else
if(!beaker)
return
else if(!beaker.reagents && !QDELETED(beaker))
beaker.create_reagents(beaker.volume)
beaker.reagents.add_reagent(input_reagent, amount)
if("makecup")
if(beaker)
return
beaker = new /obj/item/reagent_containers/glass/beaker/bluespace(src)
visible_message("<span class='notice'>[src] dispenses a bluespace beaker.</span>")
/obj/machinery/chem_dispenser/chem_synthesizer/proc/find_reagent(input)
. = FALSE
if(GLOB.chemical_reagents_list[input]) //prefer IDs!
var/datum/reagent/R = GLOB.chemical_reagents_list[input]
if(R.can_synth_debug)
return input
else
for(var/X in GLOB.chemical_reagents_list)
var/datum/reagent/R = GLOB.chemical_reagents_list[X]
if(R.can_synth_debug && input == replacetext(lowertext(R.name), " ", ""))
return X
+2 -1
View File
@@ -20,7 +20,8 @@
var/current_cycle = 0
var/volume = 0
var/color = "#000000" // rgb: 0, 0, 0
var/can_synth = TRUE
var/can_synth = TRUE // can this reagent be synthesized? (for example: odysseus syringe gun)
var/can_synth_debug = TRUE // can this reagent be synthesized by the debug chem synthesizer?
var/metabolization_rate = REAGENTS_METABOLISM //how fast the reagent is metabolized by the mob
var/overrides_metab = 0
var/overdose_threshold = 0
@@ -1546,4 +1546,70 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_desc = "It'll either knock the drunkenness out of you or knock you out cold. Both, probably."
/datum/reagent/consumable/ethanol/crevice_spike/on_mob_add(mob/living/L) //damage only applies when drink first enters system and won't again until drink metabolizes out
L.adjustBruteLoss(3 * min(5,volume)) //minimum 3 brute damage on ingestion to limit non-drink means of injury - a full 5 unit gulp of the drink trucks you for the full 15
L.adjustBruteLoss(3 * min(5,volume)) //minimum 3 brute damage on ingestion to limit non-drink means of injury - a full 5 unit gulp of the drink trucks you for the full 15
/datum/reagent/consumable/ethanol/sake
name = "Sake"
id = "sake"
description = "A sweet rice wine of questionable legality and extreme potency."
color = "#DDDDDD"
boozepwr = 70
taste_description = "sweet rice wine"
glass_icon_state = "sakecup"
glass_name = "cup of sake"
glass_desc = "A traditional cup of sake."
/datum/reagent/consumable/ethanol/alexander
name = "Alexander"
id = "alexander"
description = "A creamy, indulgent delight that is stronger than it seems."
color = "#F5E9D3"
boozepwr = 80
taste_description = "bitter, creamy cacao"
glass_icon_state = "alexander"
glass_name = "Alexander"
glass_desc = "A creamy, indulgent delight that is stronger than it seems."
/datum/reagent/consumable/ethanol/sidecar
name = "Sidecar"
id = "sidecar"
description = "The one ride youll gladly give up the wheel for."
color = "#FFC55B"
boozepwr = 80
taste_description = "delicious freedom"
glass_icon_state = "sidecar"
glass_name = "Sidecar"
glass_desc = "The one ride youll gladly give up the wheel for."
/datum/reagent/consumable/ethanol/between_the_sheets
name = "Between the Sheets"
id = "between_the_sheets"
description = "A provocatively named classic."
color = "#F4C35A"
boozepwr = 80
taste_description = "seduction"
glass_icon_state = "between_the_sheets"
glass_name = "Between the Sheets"
glass_desc = "A provocatively named classic."
/datum/reagent/consumable/ethanol/kamikaze
name = "Kamikaze"
id = "kamikaze"
description = "Divinely windy."
color = "#EEF191"
boozepwr = 60
taste_description = "divine windiness"
glass_icon_state = "kamikaze"
glass_name = "Kamikaze"
glass_desc = "Divinely windy."
/datum/reagent/consumable/ethanol/mojito
name = "Mojito"
id = "mojito"
description = "A drink that looks as refreshing as it tastes."
color = "#DFFAD9"
boozepwr = 30
taste_description = "refreshing mint"
glass_icon_state = "mojito"
glass_name = "Mojito"
glass_desc = "A drink that looks as refreshing as it tastes."
@@ -721,3 +721,13 @@
description = "Milk for cool kids."
color = "#7D4E29"
taste_description = "chocolate milk"
/datum/reagent/consumable/menthol
name = "Menthol"
id = "menthol"
description = "Tastes naturally minty, and imparts a very mild numbing sensation."
color = "#80AF9C"
taste_description = "mint"
glass_icon_state = "glass_green"
glass_name = "glass of menthol"
glass_desc = "Tastes naturally minty, and imparts a very mild numbing sensation."
@@ -57,15 +57,6 @@
..()
. = 1
/datum/reagent/drug/menthol
name = "Menthol"
id = "menthol"
description = "Tastes naturally minty, and imparts a very mild numbing sensation."
taste_description = "mint"
reagent_state = LIQUID
color = "#80AF9C"
trippy = FALSE
/datum/reagent/drug/crank
name = "Crank"
id = "crank"
@@ -171,8 +171,7 @@
else if(istype(O, /obj/item/stack/sheet/hairlesshide))
var/obj/item/stack/sheet/hairlesshide/HH = O
var/obj/item/stack/sheet/wetleather/WL = new(get_turf(HH))
WL.amount = HH.amount
new /obj/item/stack/sheet/wetleather(get_turf(HH), HH.amount)
qdel(HH)
/*
@@ -728,7 +728,7 @@
/datum/reagent/toxin/rotatium/on_mob_life(mob/living/M)
if(M.hud_used)
if(current_cycle >= 20 && current_cycle%20 == 0)
var/list/screens = list(M.hud_used.plane_masters["[GAME_PLANE]"], M.hud_used.plane_masters["[LIGHTING_PLANE]"])
var/list/screens = list(M.hud_used.plane_masters["[FLOOR_PLANE]"], M.hud_used.plane_masters["[GAME_PLANE]"], M.hud_used.plane_masters["[LIGHTING_PLANE]"])
var/rotation = min(round(current_cycle/20), 89) // By this point the player is probably puking and quitting anyway
for(var/whole_screen in screens)
animate(whole_screen, transform = matrix(rotation, MATRIX_ROTATE), time = 5, easing = QUAD_EASING, loop = -1)
@@ -737,7 +737,7 @@
/datum/reagent/toxin/rotatium/on_mob_delete(mob/living/M)
if(M && M.hud_used)
var/list/screens = list(M.hud_used.plane_masters["[GAME_PLANE]"], M.hud_used.plane_masters["[LIGHTING_PLANE]"])
var/list/screens = list(M.hud_used.plane_masters["[FLOOR_PLANE]"], M.hud_used.plane_masters["[GAME_PLANE]"], M.hud_used.plane_masters["[LIGHTING_PLANE]"])
for(var/whole_screen in screens)
animate(whole_screen, transform = matrix(), time = 5, easing = QUAD_EASING)
..()
@@ -755,7 +755,7 @@
/datum/reagent/toxin/skewium/on_mob_life(mob/living/M)
if(M.hud_used)
if(current_cycle >= 5 && current_cycle % 3 == 0)
var/list/screens = list(M.hud_used.plane_masters["[GAME_PLANE]"], M.hud_used.plane_masters["[LIGHTING_PLANE]"])
var/list/screens = list(M.hud_used.plane_masters["[FLOOR_PLANE]"], M.hud_used.plane_masters["[GAME_PLANE]"], M.hud_used.plane_masters["[LIGHTING_PLANE]"])
var/matrix/skew = matrix()
var/intensity = 8
skew.set_skew(rand(-intensity,intensity), rand(-intensity,intensity))
@@ -772,7 +772,7 @@
/datum/reagent/toxin/skewium/on_mob_delete(mob/living/M)
if(M && M.hud_used)
var/list/screens = list(M.hud_used.plane_masters["[GAME_PLANE]"], M.hud_used.plane_masters["[LIGHTING_PLANE]"])
var/list/screens = list(M.hud_used.plane_masters["[FLOOR_PLANE]"], M.hud_used.plane_masters["[GAME_PLANE]"], M.hud_used.plane_masters["[LIGHTING_PLANE]"])
for(var/whole_screen in screens)
animate(whole_screen, transform = matrix(), time = 5, easing = QUAD_EASING)
..()
+3 -2
View File
@@ -51,8 +51,9 @@ other types of metals and chemistry for reagents).
return ..()
/datum/design/proc/icon_html(client/user)
send_asset(user, "design_[id].png", FALSE)
return "<img class='icon' src=\"design_[id].png\">"
var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/research_designs)
sheet.send(user)
return sheet.icon_tag(id)
////////////////////////////////////////
//Disks for transporting design datums//

Some files were not shown because too many files have changed in this diff Show More