Merge remote-tracking branch 'polaris/master' into pixel_projectiles

This commit is contained in:
kevinz000
2018-12-10 15:54:00 -08:00
1410 changed files with 35515 additions and 14660 deletions
+4 -4
View File
@@ -159,14 +159,14 @@
if(burning)
burning = FALSE
update_icon()
processing_objects -= src
STOP_PROCESSING(SSobj, src)
visible_message("<span class='notice'>\The [src] stops burning.</span>")
/obj/structure/bonfire/proc/ignite()
if(!burning && get_fuel_amount())
burning = TRUE
update_icon()
processing_objects += src
START_PROCESSING(SSobj, src)
visible_message("<span class='warning'>\The [src] starts burning!</span>")
/obj/structure/bonfire/proc/burn()
@@ -342,14 +342,14 @@
if(burning)
burning = FALSE
update_icon()
processing_objects -= src
STOP_PROCESSING(SSobj, src)
visible_message("<span class='notice'>\The [src] stops burning.</span>")
/obj/structure/fireplace/proc/ignite()
if(!burning && get_fuel_amount())
burning = TRUE
update_icon()
processing_objects += src
START_PROCESSING(SSobj, src)
visible_message("<span class='warning'>\The [src] starts burning!</span>")
/obj/structure/fireplace/proc/burn()
+1 -1
View File
@@ -11,7 +11,7 @@
var/maxhealth = 100
anchored = 1.0
/obj/structure/catwalk/initialize()
/obj/structure/catwalk/Initialize()
. = ..()
for(var/obj/structure/catwalk/O in range(1))
O.update_icon()
@@ -9,22 +9,30 @@
var/icon_closed = "closed"
var/icon_opened = "open"
var/opened = 0
var/welded = 0
var/sealed = 0
var/seal_tool = /obj/item/weapon/weldingtool //Tool used to seal the closet, defaults to welder
var/wall_mounted = 0 //never solid (You can always pass over it)
var/health = 100
var/breakout = 0 //if someone is currently breaking out. mutex
var/breakout_time = 2 //2 minutes by default
var/breakout_sound = 'sound/effects/grillehit.ogg' //Sound that plays while breaking out
var/storage_capacity = 2 * MOB_MEDIUM //This is so that someone can't pack hundreds of items in a locker/crate
//then open it in a populated area to crash clients.
var/storage_cost = 40 //How much space this closet takes up if it's stuffed in another closet
var/open_sound = 'sound/machines/click.ogg'
var/close_sound = 'sound/machines/click.ogg'
var/store_misc = 1
var/store_items = 1
var/store_mobs = 1
var/store_misc = 1 //Chameleon item check
var/store_items = 1 //Will the closet store items?
var/store_mobs = 1 //Will the closet store mobs?
var/max_closets = 0 //Number of other closets allowed on tile before it won't close.
var/list/starts_with
/obj/structure/closet/initialize()
/obj/structure/closet/Initialize()
. = ..()
if(starts_with)
create_objects_in_loc(src, starts_with)
@@ -38,27 +46,27 @@
// adjust locker size to hold all items with 5 units of free store room
var/content_size = 0
for(I in src.contents)
content_size += Ceiling(I.w_class/2)
content_size += CEILING(I.w_class/2, 1)
if(content_size > storage_capacity-5)
storage_capacity = content_size + 5
update_icon()
/obj/structure/closet/examine(mob/user)
if(..(user, 1) && !opened)
var/content_size = 0
for(var/obj/item/I in src.contents)
if(!I.anchored)
content_size += Ceiling(I.w_class/2)
content_size += CEILING(I.w_class/2, 1)
if(!content_size)
user << "It is empty."
to_chat(user, "It is empty.")
else if(storage_capacity > content_size*4)
user << "It is barely filled."
to_chat(user, "It is barely filled.")
else if(storage_capacity > content_size*2)
user << "It is less than half full."
to_chat(user, "It is less than half full.")
else if(storage_capacity > content_size)
user << "There is still some free space."
to_chat(user, "There is still some free space.")
else
user << "It is full."
to_chat(user, "It is full.")
/obj/structure/closet/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
if(wall_mounted)
@@ -66,14 +74,18 @@
return ..()
/obj/structure/closet/proc/can_open()
if(src.welded)
if(src.sealed)
return 0
return 1
/obj/structure/closet/proc/can_close()
var/closet_count = 0
for(var/obj/structure/closet/closet in get_turf(src))
if(closet != src)
return 0
if(!closet.anchored)
closet_count ++
if(closet_count > max_closets)
return 0
return 1
/obj/structure/closet/proc/dump_contents()
@@ -102,7 +114,7 @@
src.icon_state = src.icon_opened
src.opened = 1
playsound(src.loc, open_sound, 15, 1, -3)
density = 0
density = !density
return 1
/obj/structure/closet/proc/close()
@@ -119,12 +131,14 @@
stored_units += store_items(stored_units)
if(store_mobs)
stored_units += store_mobs(stored_units)
if(max_closets)
stored_units += store_closets(stored_units)
src.icon_state = src.icon_closed
src.opened = 0
playsound(src.loc, close_sound, 15, 1, -3)
density = 1
density = !density
return 1
//Cham Projector Exception
@@ -140,7 +154,7 @@
/obj/structure/closet/proc/store_items(var/stored_units)
var/added_units = 0
for(var/obj/item/I in src.loc)
var/item_size = Ceiling(I.w_class / 2)
var/item_size = CEILING(I.w_class / 2, 1)
if(stored_units + added_units + item_size > storage_capacity)
continue
if(!I.anchored)
@@ -162,9 +176,25 @@
added_units += M.mob_size
return added_units
/obj/structure/closet/proc/store_closets(var/stored_units)
var/added_units = 0
for(var/obj/structure/closet/C in src.loc)
if(C == src) //Don't store ourself
continue
if(C.anchored) //Don't worry about anchored things on the same tile
continue
if(C.max_closets) //Prevents recursive storage
continue
if(stored_units + added_units + storage_cost > storage_capacity)
break
C.forceMove(src)
added_units += storage_cost
return added_units
/obj/structure/closet/proc/toggle(mob/user as mob)
if(!(src.opened ? src.close() : src.open()))
user << "<span class='notice'>It won't budge!</span>"
to_chat(user, "<span class='notice'>It won't budge!</span>")
return
update_icon()
@@ -222,7 +252,7 @@
if(!WT.isOn())
return
else
user << "<span class='notice'>You need more welding fuel to complete this task.</span>"
to_chat(user, "<span class='notice'>You need more welding fuel to complete this task.</span>")
return
playsound(src, WT.usesound, 50)
new /obj/item/stack/material/steel(src.loc)
@@ -248,21 +278,25 @@
W.forceMove(src.loc)
else if(istype(W, /obj/item/weapon/packageWrap))
return
else if(istype(W, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/WT = W
if(!WT.remove_fuel(0,user))
if(!WT.isOn())
return
else
user << "<span class='notice'>You need more welding fuel to complete this task.</span>"
return
playsound(src, WT.usesound, 50)
src.welded = !src.welded
src.update_icon()
for(var/mob/M in viewers(src))
M.show_message("<span class='warning'>[src] has been [welded?"welded shut":"unwelded"] by [user.name].</span>", 3, "You hear welding.", 2)
else if(seal_tool)
if(istype(W, seal_tool))
var/obj/item/weapon/S = W
if(istype(S, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/WT = S
if(!WT.remove_fuel(0,user))
if(!WT.isOn())
return
else
to_chat(user, "<span class='notice'>You need more welding fuel to complete this task.</span>")
return
if(do_after(user, 20 * S.toolspeed))
playsound(src, S.usesound, 50)
src.sealed = !src.sealed
src.update_icon()
for(var/mob/M in viewers(src))
M.show_message("<span class='warning'>[src] has been [sealed?"sealed":"unsealed"] by [user.name].</span>", 3)
else if(W.is_wrench())
if(welded)
if(sealed)
if(anchored)
user.visible_message("\The [user] begins unsecuring \the [src] from the floor.", "You start unsecuring \the [src] from the floor.")
else
@@ -270,7 +304,7 @@
playsound(src, W.usesound, 50)
if(do_after(user, 20 * W.toolspeed))
if(!src) return
user << "<span class='notice'>You [anchored? "un" : ""]secured \the [src]!</span>"
to_chat(user, "<span class='notice'>You [anchored? "un" : ""]secured \the [src]!</span>")
anchored = !anchored
else
src.attack_hand(user)
@@ -306,7 +340,7 @@
return
if(!src.open())
user << "<span class='notice'>It won't budge!</span>"
to_chat(user, "<span class='notice'>It won't budge!</span>")
/obj/structure/closet/attack_hand(mob/user as mob)
src.add_fingerprint(user)
@@ -316,7 +350,7 @@
/obj/structure/closet/attack_self_tk(mob/user as mob)
src.add_fingerprint(user)
if(!src.toggle())
usr << "<span class='notice'>It won't budge!</span>"
to_chat(usr, "<span class='notice'>It won't budge!</span>")
/obj/structure/closet/attack_ghost(mob/ghost)
if(ghost.client && ghost.client.inquisitive_ghost)
@@ -336,19 +370,19 @@
src.add_fingerprint(usr)
src.toggle(usr)
else
usr << "<span class='warning'>This mob type can't use this verb.</span>"
to_chat(usr, "<span class='warning'>This mob type can't use this verb.</span>")
/obj/structure/closet/update_icon()//Putting the welded stuff in updateicon() so it's easy to overwrite for special cases (Fridges, cabinets, and whatnot)
/obj/structure/closet/update_icon()//Putting the sealed stuff in updateicon() so it's easy to overwrite for special cases (Fridges, cabinets, and whatnot)
overlays.Cut()
if(!opened)
icon_state = icon_closed
if(welded)
overlays += "welded"
if(sealed)
overlays += "sealed"
else
icon_state = icon_opened
/obj/structure/closet/attack_generic(var/mob/user, var/damage, var/attack_message = "destroys", var/wallbreaker)
if(damage < 10 || !wallbreaker)
/obj/structure/closet/attack_generic(var/mob/user, var/damage, var/attack_message = "destroys")
if(damage < STRUCTURE_MIN_DAMAGE_THRESHOLD)
return
user.do_attack_animation(src)
visible_message("<span class='danger'>[user] [attack_message] the [src]!</span>")
@@ -359,20 +393,19 @@
/obj/structure/closet/proc/req_breakout()
if(opened)
return 0 //Door's open... wait, why are you in it's contents then?
if(!welded)
return 0 //closed but not welded...
if(!sealed)
return 0 //closed but not sealed...
return 1
/obj/structure/closet/proc/mob_breakout(var/mob/living/escapee)
var/breakout_time = 2 //2 minutes by default
if(breakout || !req_breakout())
return
escapee.setClickCooldown(100)
//okay, so the closet is either welded or locked... resist!!!
escapee << "<span class='warning'>You lean on the back of \the [src] and start pushing the door open. (this will take about [breakout_time] minutes)</span>"
//okay, so the closet is either sealed or locked... resist!!!
to_chat(escapee, "<span class='warning'>You lean on the back of \the [src] and start pushing the door open. (this will take about [breakout_time] minutes)</span>")
visible_message("<span class='danger'>\The [src] begins to shake violently!</span>")
@@ -389,20 +422,20 @@
breakout = 0
return
playsound(src.loc, 'sound/effects/grillehit.ogg', 100, 1)
playsound(src.loc, breakout_sound, 100, 1)
animate_shake()
add_fingerprint(escapee)
//Well then break it!
breakout = 0
escapee << "<span class='warning'>You successfully break out!</span>"
to_chat(escapee, "<span class='warning'>You successfully break out!</span>")
visible_message("<span class='danger'>\The [escapee] successfully broke out of \the [src]!</span>")
playsound(src.loc, 'sound/effects/grillehit.ogg', 100, 1)
playsound(src.loc, breakout_sound, 100, 1)
break_open()
animate_shake()
/obj/structure/closet/proc/break_open()
welded = 0
sealed = 0
update_icon()
//Do this to prevent contents from being opened into nullspace (read: bluespace)
if(istype(loc, /obj/structure/bigDelivery))
@@ -421,3 +454,9 @@
/obj/structure/closet/AllowDrop()
return TRUE
/obj/structure/closet/return_air_for_internal_lifeform(var/mob/living/L)
if(src.loc)
if(istype(src.loc, /obj/structure/closet))
return (loc.return_air_for_internal_lifeform(L))
return return_air()
@@ -4,9 +4,161 @@
icon_state = "coffin"
icon_closed = "coffin"
icon_opened = "coffin_open"
seal_tool = /obj/item/weapon/tool/screwdriver
breakout_sound = 'sound/weapons/tablehit1.ogg'
/obj/structure/closet/coffin/update_icon()
if(!opened)
icon_state = icon_closed
else
icon_state = icon_opened
/* Graves */
/obj/structure/closet/grave
name = "grave"
desc = "Dirt."
icon_state = "grave"
icon_closed = "grave"
icon_opened = "grave_open"
seal_tool = null
breakout_sound = 'sound/weapons/thudswoosh.ogg'
anchored = 1
max_closets = 1
opened = 1
/obj/structure/closet/grave/attack_hand(mob/user as mob)
if(opened)
visible_message("<span class='notice'>[user] starts to climb into \the [src.name].</span>", \
"<span class='notice'>You start to lower yourself into \the [src.name].</span>")
if(do_after(user, 50))
user.forceMove(src.loc)
visible_message("<span class='notice'>[user] climbs into \the [src.name].</span>", \
"<span class='notice'>You climb into \the [src.name].</span>")
else
visible_message("<span class='notice'>[user] decides not to climb into \the [src.name].</span>", \
"<span class='notice'>You stop climbing into \the [src.name].</span>")
return
/obj/structure/closet/grave/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
if(opened && ismob(mover))
var/mob/M = mover
add_fingerprint(M)
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(H.m_intent == "walk")
to_chat(H, "<span class='warning'>You stop at the edge of \the [src.name].</span>")
return FALSE
else
to_chat(H, "<span class='warning'>You fall into \the [src.name]!</span>")
fall_in(H)
return TRUE
if(isrobot(M))
var/mob/living/silicon/robot/R = M
if(R.a_intent == I_HELP)
to_chat(R, "<span class='warning'>You stop at the edge of \the [src.name].</span>")
return FALSE
else
to_chat(R, "<span class='warning'>You enter \the [src.name].</span>")
return TRUE
return TRUE //Everything else can move over the graves
/obj/structure/closet/grave/proc/fall_in(mob/living/L) //Only called on humans for now, but still
L.Weaken(5)
if(ishuman(L))
var/mob/living/carbon/human/H = L
var/limb_damage = rand(5,25)
H.adjustBruteLoss(limb_damage)
/obj/structure/closet/grave/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(src.opened)
if(istype(W, /obj/item/weapon/shovel))
user.visible_message("<span class='notice'>[user] piles dirt into \the [src.name].</span>", \
"<span class='notice'>You start to pile dirt into \the [src.name].</span>", \
"<span class='notice'>You hear dirt being moved.</span>")
if(do_after(user, 40 * W.toolspeed))
user.visible_message("<span class='notice'>[user] pats down the dirt on top of \the [src.name].</span>", \
"<span class='notice'>You finish filling in \the [src.name].</span>")
close()
return
else
user.visible_message("<span class='notice'>[user] stops filling in \the [src.name].</span>", \
"<span class='notice'>You change your mind and stop filling in \the [src.name].</span>")
return
if(istype(W, /obj/item/weapon/grab))
var/obj/item/weapon/grab/G = W
src.MouseDrop_T(G.affecting, user) //act like they were dragged onto the closet
return 0
if(istype(W,/obj/item/tk_grab))
return 0
if(istype(W, /obj/item/weapon/storage/laundry_basket) && W.contents.len)
var/obj/item/weapon/storage/laundry_basket/LB = W
var/turf/T = get_turf(src)
for(var/obj/item/I in LB.contents)
LB.remove_from_storage(I, T)
user.visible_message("<span class='notice'>[user] empties \the [LB] into \the [src].</span>", \
"<span class='notice'>You empty \the [LB] into \the [src].</span>", \
"<span class='notice'>You hear rustling of clothes.</span>")
return
if(isrobot(user))
return
if(W.loc != user) // This should stop mounted modules ending up outside the module.
return
usr.drop_item()
if(W)
W.forceMove(src.loc)
else
if(istype(W, /obj/item/weapon/shovel))
if(user.a_intent == I_HURT) // Hurt intent means you're trying to kill someone, or just get rid of the grave
user.visible_message("<span class='notice'>[user] begins to smoothe out the dirt of \the [src.name].</span>", \
"<span class='notice'>You start to smoothe out the dirt of \the [src.name].</span>", \
"<span class='notice'>You hear dirt being moved.</span>")
if(do_after(user, 40 * W.toolspeed))
user.visible_message("<span class='notice'>[user] finishes smoothing out \the [src.name].</span>", \
"<span class='notice'>You finish smoothing out \the [src.name].</span>")
if(LAZYLEN(contents))
alpha = 40 // If we've got stuff inside, like maybe a person, just make it hard to see us
else
qdel(src) // Else, go away
return
else
user.visible_message("<span class='notice'>[user] stops concealing \the [src.name].</span>", \
"<span class='notice'>You stop concealing \the [src.name].</span>")
return
else
user.visible_message("<span class='notice'>[user] begins to unearth \the [src.name].</span>", \
"<span class='notice'>You start to unearth \the [src.name].</span>", \
"<span class='notice'>You hear dirt being moved.</span>")
if(do_after(user, 40 * W.toolspeed))
user.visible_message("<span class='notice'>[user] reaches the bottom of \the [src.name].</span>", \
"<span class='notice'>You finish digging out \the [src.name].</span>")
break_open()
return
else
user.visible_message("<span class='notice'>[user] stops digging out \the [src.name].</span>", \
"<span class='notice'>You stop digging out \the [src.name].</span>")
return
return
/obj/structure/closet/grave/close()
..()
if(!opened)
sealed = TRUE
/obj/structure/closet/grave/open()
.=..()
alpha = 255 // Needed because of grave hiding
/obj/structure/closet/grave/bullet_act(var/obj/item/projectile/P)
return PROJECTILE_CONTINUE // It's a hole in the ground, doesn't usually stop or even care about bullets
/obj/structure/closet/grave/return_air_for_internal_lifeform(var/mob/living/L)
var/gasid = "carbon_dioxide"
if(ishuman(L))
var/mob/living/carbon/human/H = L
if(H.species && H.species.exhale_type)
gasid = H.species.exhale_type
var/datum/gas_mixture/grave_breath = new()
var/datum/gas_mixture/above_air = return_air()
grave_breath.adjust_gas(gasid, BREATH_MOLES)
grave_breath.temperature = (above_air.temperature) - 30 //Underground
return grave_breath
@@ -16,7 +16,7 @@
starts_with = list(/obj/item/weapon/material/twohanded/fireaxe)
/obj/structure/closet/fireaxecabinet/initialize()
/obj/structure/closet/fireaxecabinet/Initialize()
..()
fireaxe = locate() in contents
@@ -22,7 +22,7 @@
/obj/item/clothing/gloves/fingerless,
/obj/item/clothing/head/soft)
/obj/structure/closet/secure_closet/cargotech/initialize()
/obj/structure/closet/secure_closet/cargotech/Initialize()
if(prob(75))
starts_with += /obj/item/weapon/storage/backpack
else
@@ -59,7 +59,7 @@
/obj/item/clothing/suit/storage/hooded/wintercoat/cargo,
/obj/item/clothing/shoes/boots/winter/supply)
/obj/structure/closet/secure_closet/quartermaster/initialize()
/obj/structure/closet/secure_closet/quartermaster/Initialize()
if(prob(75))
starts_with += /obj/item/weapon/storage/backpack
else
@@ -93,7 +93,7 @@
/obj/item/clothing/shoes/boots/winter/mining,
/obj/item/stack/marker_beacon/thirty)
/obj/structure/closet/secure_closet/miner/initialize()
/obj/structure/closet/secure_closet/miner/Initialize()
if(prob(50))
starts_with += /obj/item/weapon/storage/backpack/industrial
else
@@ -32,7 +32,7 @@
/obj/item/clothing/shoes/boots/winter/engineering,
/obj/item/weapon/tank/emergency/oxygen/engi)
/obj/structure/closet/secure_closet/engineering_chief/initialize()
/obj/structure/closet/secure_closet/engineering_chief/Initialize()
if(prob(50))
starts_with += /obj/item/weapon/storage/backpack/industrial
else
@@ -98,7 +98,7 @@
/obj/item/clothing/shoes/boots/winter/engineering,
/obj/item/weapon/tank/emergency/oxygen/engi)
/obj/structure/closet/secure_closet/engineering_personal/initialize()
/obj/structure/closet/secure_closet/engineering_personal/Initialize()
if(prob(50))
starts_with += /obj/item/weapon/storage/backpack/industrial
else
@@ -133,7 +133,7 @@
/obj/item/clothing/shoes/boots/winter/atmos,
/obj/item/weapon/tank/emergency/oxygen/engi)
/obj/structure/closet/secure_closet/atmos_personal/initialize()
/obj/structure/closet/secure_closet/atmos_personal/Initialize()
if(prob(50))
starts_with += /obj/item/weapon/storage/backpack/industrial
else
@@ -9,7 +9,7 @@
icon_opened = "base"
req_one_access = list(access_armory)
/obj/structure/closet/secure_closet/guncabinet/initialize()
/obj/structure/closet/secure_closet/guncabinet/Initialize()
. = ..()
update_icon()
@@ -43,8 +43,8 @@
overlays += icon(src.icon, "door")
if(welded)
overlays += icon(src.icon,"welded")
if(sealed)
overlays += icon(src.icon,"sealed")
if(broken)
overlays += icon(src.icon,"broken")
@@ -16,12 +16,12 @@
/obj/item/clothing/head/greenbandana,
/obj/item/weapon/material/minihoe,
/obj/item/weapon/material/knife/machete/hatchet,
/obj/item/weapon/tool/wirecutters/clippers,
/obj/item/weapon/tool/wirecutters/clippers/trimmers,
/obj/item/weapon/reagent_containers/spray/plantbgone,
/obj/item/clothing/suit/storage/hooded/wintercoat/hydro,
/obj/item/clothing/shoes/boots/winter/hydro)
/obj/structure/closet/secure_closet/hydroponics/initialize()
/obj/structure/closet/secure_closet/hydroponics/Initialize()
if(prob(50))
starts_with += /obj/item/clothing/suit/storage/apron
else
@@ -60,7 +60,7 @@
/obj/item/clothing/head/nursehat,
/obj/item/weapon/storage/box/freezer = 3)
/obj/structure/closet/secure_closet/medical3/initialize()
/obj/structure/closet/secure_closet/medical3/Initialize()
if(prob(50))
starts_with += /obj/item/weapon/storage/backpack/medic
else
@@ -169,7 +169,7 @@
/obj/item/clothing/head/bio_hood/cmo,
/obj/item/clothing/shoes/white)
/obj/structure/closet/secure_closet/CMO/initialize()
/obj/structure/closet/secure_closet/CMO/Initialize()
if(prob(50))
starts_with += /obj/item/weapon/storage/backpack/medic
else
@@ -7,7 +7,7 @@
starts_with = list(
/obj/item/device/radio/headset)
/obj/structure/closet/secure_closet/personal/initialize()
/obj/structure/closet/secure_closet/personal/Initialize()
if(prob(50))
starts_with += /obj/item/weapon/storage/backpack
else
@@ -18,7 +18,7 @@
/obj/item/clothing/suit/storage/hooded/wintercoat/science,
/obj/item/clothing/shoes/boots/winter/science)
/obj/structure/closet/secure_closet/scientist/initialize()
/obj/structure/closet/secure_closet/scientist/Initialize()
if(prob(50))
starts_with += /obj/item/weapon/storage/backpack/dufflebag/sci
else
@@ -46,23 +46,23 @@
/obj/structure/closet/secure_closet/proc/togglelock(mob/user as mob)
if(src.opened)
user << "<span class='notice'>Close the locker first.</span>"
to_chat(user, "<span class='notice'>Close the locker first.</span>")
return
if(src.broken)
user << "<span class='warning'>The locker appears to be broken.</span>"
to_chat(user, "<span class='warning'>The locker appears to be broken.</span>")
return
if(user.loc == src)
user << "<span class='notice'>You can't reach the lock from inside.</span>"
to_chat(user, "<span class='notice'>You can't reach the lock from inside.</span>")
return
if(src.allowed(user))
src.locked = !src.locked
playsound(src.loc, 'sound/machines/click.ogg', 15, 1, -3)
for(var/mob/O in viewers(user, 3))
if((O.client && !( O.blinded )))
O << "<span class='notice'>The locker has been [locked ? null : "un"]locked by [user].</span>"
to_chat(O, "<span class='notice'>The locker has been [locked ? null : "un"]locked by [user].</span>")
update_icon()
else
user << "<span class='notice'>Access Denied</span>"
to_chat(user, "<span class='notice'>Access Denied</span>")
/obj/structure/closet/secure_closet/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(src.opened)
@@ -73,7 +73,7 @@
if(src.large)
src.MouseDrop_T(G.affecting, user) //act like they were dragged onto the closet
else
user << "<span class='notice'>The locker is too small to stuff [G.affecting] into!</span>"
to_chat(user, "<span class='notice'>The locker is too small to stuff [G.affecting] into!</span>")
if(isrobot(user))
return
if(W.loc != user) // This should stop mounted modules ending up outside the module.
@@ -89,14 +89,14 @@
playsound(src.loc, 'sound/weapons/blade1.ogg', 50, 1)
playsound(src.loc, "sparks", 50, 1)
else if(W.is_wrench())
if(welded)
if(sealed)
if(anchored)
user.visible_message("\The [user] begins unsecuring \the [src] from the floor.", "You start unsecuring \the [src] from the floor.")
else
user.visible_message("\The [user] begins securing \the [src] to the floor.", "You start securing \the [src] to the floor.")
if(do_after(user, 20 * W.toolspeed))
if(!src) return
user << "<span class='notice'>You [anchored? "un" : ""]secured \the [src]!</span>"
to_chat(user, "<span class='notice'>You [anchored? "un" : ""]secured \the [src]!</span>")
anchored = !anchored
return
else if(istype(W,/obj/item/weapon/packageWrap) || istype(W,/obj/item/weapon/weldingtool))
@@ -143,9 +143,9 @@
src.add_fingerprint(usr)
src.togglelock(usr)
else
usr << "<span class='warning'>This mob type can't use this verb.</span>"
to_chat(usr, "<span class='warning'>This mob type can't use this verb.</span>")
/obj/structure/closet/secure_closet/update_icon()//Putting the welded stuff in updateicon() so it's easy to overwrite for special cases (Fridges, cabinets, and whatnot)
/obj/structure/closet/secure_closet/update_icon()//Putting the sealed stuff in updateicon() so it's easy to overwrite for special cases (Fridges, cabinets, and whatnot)
overlays.Cut()
if(!opened)
@@ -155,8 +155,8 @@
icon_state = icon_locked
else
icon_state = icon_closed
if(welded)
overlays += "welded"
if(sealed)
overlays += "sealed"
else
icon_state = icon_opened
@@ -119,7 +119,7 @@
/obj/item/device/flashlight/maglight,
/obj/item/clothing/mask/gas/half)
/obj/structure/closet/secure_closet/hos/initialize()
/obj/structure/closet/secure_closet/hos/Initialize()
if(prob(50))
starts_with += /obj/item/weapon/storage/backpack/security
else
@@ -168,7 +168,7 @@
/obj/item/device/megaphone,
/obj/item/clothing/mask/gas/half)
/obj/structure/closet/secure_closet/warden/initialize()
/obj/structure/closet/secure_closet/warden/Initialize()
if(prob(50))
starts_with += /obj/item/weapon/storage/backpack/security
else
@@ -212,7 +212,7 @@
/obj/item/clothing/shoes/boots/winter/security,
/obj/item/device/flashlight/maglight)
/obj/structure/closet/secure_closet/security/initialize()
/obj/structure/closet/secure_closet/security/Initialize()
if(prob(50))
starts_with += /obj/item/weapon/storage/backpack/security
else
@@ -221,22 +221,22 @@
starts_with += /obj/item/weapon/storage/backpack/dufflebag/sec
return ..()
/obj/structure/closet/secure_closet/security/cargo/initialize()
/obj/structure/closet/secure_closet/security/cargo/Initialize()
starts_with += /obj/item/clothing/accessory/armband/cargo
starts_with += /obj/item/device/encryptionkey/headset_cargo
return ..()
/obj/structure/closet/secure_closet/security/engine/initialize()
/obj/structure/closet/secure_closet/security/engine/Initialize()
starts_with += /obj/item/clothing/accessory/armband/engine
starts_with += /obj/item/device/encryptionkey/headset_eng
return ..()
/obj/structure/closet/secure_closet/security/science/initialize()
/obj/structure/closet/secure_closet/security/science/Initialize()
starts_with += /obj/item/clothing/accessory/armband/science
starts_with += /obj/item/device/encryptionkey/headset_sci
return ..()
/obj/structure/closet/secure_closet/security/med/initialize()
/obj/structure/closet/secure_closet/security/med/Initialize()
starts_with += /obj/item/clothing/accessory/armband/medblue
starts_with += /obj/item/device/encryptionkey/headset_med
return ..()
@@ -43,7 +43,7 @@
qdel(src)
return
processing_objects.Add(src)
START_PROCESSING(SSobj, src)
..()
/obj/structure/closet/statue/process()
@@ -55,7 +55,7 @@
M.setOxyLoss(intialOxy)
if (timer <= 0)
dump_contents()
processing_objects.Remove(src)
STOP_PROCESSING(SSobj, src)
qdel(src)
/obj/structure/closet/statue/dump_contents()
@@ -48,7 +48,7 @@
/obj/structure/closet/syndicate/resources
desc = "An old, dusty locker."
/obj/structure/closet/syndicate/resources/initialize()
/obj/structure/closet/syndicate/resources/Initialize()
. = ..()
if(!contents.len)
var/common_min = 30 //Minimum amount of minerals in the stack for common minerals
@@ -103,7 +103,7 @@
/obj/structure/closet/syndicate/resources/everything
desc = "It's an emergency storage closet for repairs."
/obj/structure/closet/syndicate/resources/everything/initialize()
/obj/structure/closet/syndicate/resources/everything/Initialize()
var/list/resources = list(
/obj/item/stack/material/steel,
/obj/item/stack/material/glass,
@@ -19,7 +19,7 @@
icon_closed = "emergency"
icon_opened = "emergencyopen"
/obj/structure/closet/emcloset/initialize()
/obj/structure/closet/emcloset/Initialize()
switch (pickweight(list("small" = 55, "aid" = 25, "tank" = 10, "both" = 10)))
if ("small")
starts_with = list(
@@ -106,7 +106,7 @@
icon_closed = "toolcloset"
icon_opened = "toolclosetopen"
/obj/structure/closet/toolcloset/initialize()
/obj/structure/closet/toolcloset/Initialize()
starts_with = list()
if(prob(40))
starts_with += /obj/item/clothing/suit/storage/hazardvest
@@ -22,7 +22,7 @@
/obj/item/clothing/accessory/armband = 3,
/obj/item/clothing/accessory/holster/waist = 3)
/obj/structure/closet/wardrobe/red/initialize()
/obj/structure/closet/wardrobe/red/Initialize()
if(prob(50))
starts_with += /obj/item/weapon/storage/backpack/security
else
@@ -223,7 +223,7 @@
/obj/item/weapon/storage/backpack/toxins,
/obj/item/weapon/storage/backpack/satchel/tox)
/obj/structure/closet/wardrobe/science_white/initialize()
/obj/structure/closet/wardrobe/science_white/Initialize()
if(prob(50))
starts_with += /obj/item/weapon/storage/backpack/dufflebag/sci
else
@@ -249,7 +249,7 @@
/obj/item/weapon/storage/backpack/toxins,
/obj/item/weapon/storage/backpack/satchel/tox)
/obj/structure/closet/wardrobe/robotics_black/initialize()
/obj/structure/closet/wardrobe/robotics_black/Initialize()
if(prob(50))
starts_with += /obj/item/weapon/storage/backpack/dufflebag/sci
else
@@ -401,7 +401,7 @@
/obj/item/clothing/gloves/black,
/obj/item/clothing/under/pants/camo)
/obj/structure/closet/wardrobe/tactical/initialize()
/obj/structure/closet/wardrobe/tactical/Initialize()
if(prob(25))
starts_with += /obj/item/weapon/storage/belt/security/tactical/bandolier
else
@@ -6,7 +6,7 @@
density = 1
var/list/starts_with
/obj/structure/largecrate/initialize()
/obj/structure/largecrate/Initialize()
. = ..()
if(starts_with)
create_objects_in_loc(src, starts_with)
@@ -15,6 +15,7 @@
if(I.density || I.anchored || I == src || !I.simulated)
continue
I.forceMove(src)
update_icon()
/obj/structure/largecrate/attack_hand(mob/user as mob)
to_chat(user, "<span class='notice'>You need a crowbar to pry this open!</span>")
@@ -57,6 +58,29 @@
ME.attach(H)
..()
/obj/structure/largecrate/vehicle
name = "vehicle crate"
desc = "It comes in a box for the consumer's sake. ..How is this lighter?"
icon_state = "vehiclecrate"
/obj/structure/largecrate/vehicle/Initialize()
..()
spawn(1)
for(var/obj/O in contents)
O.update_icon()
/obj/structure/largecrate/vehicle/bike
name = "spacebike crate"
starts_with = list(/obj/structure/vehiclecage/spacebike)
/obj/structure/largecrate/vehicle/quadbike
name = "\improper ATV crate"
starts_with = list(/obj/structure/vehiclecage/quadbike)
/obj/structure/largecrate/vehicle/quadtrailer
name = "\improper ATV trailer crate"
starts_with = list(/obj/structure/vehiclecage/quadtrailer)
/obj/structure/largecrate/animal
icon_state = "mulecrate"
@@ -66,23 +90,23 @@
/obj/structure/largecrate/animal/corgi
name = "corgi carrier"
starts_with = list(/mob/living/simple_animal/corgi)
starts_with = list(/mob/living/simple_mob/animal/passive/dog/corgi)
/obj/structure/largecrate/animal/cow
name = "cow crate"
starts_with = list(/mob/living/simple_animal/cow)
starts_with = list(/mob/living/simple_mob/animal/passive/cow)
/obj/structure/largecrate/animal/goat
name = "goat crate"
starts_with = list(/mob/living/simple_animal/retaliate/goat)
starts_with = list(/mob/living/simple_mob/animal/goat)
/obj/structure/largecrate/animal/cat
name = "cat carrier"
starts_with = list(/mob/living/simple_animal/cat)
starts_with = list(/mob/living/simple_mob/animal/passive/cat)
/obj/structure/largecrate/animal/cat/bones
starts_with = list(/mob/living/simple_animal/cat/fluff/bones)
starts_with = list(/mob/living/simple_mob/animal/passive/cat/bones)
/obj/structure/largecrate/animal/chick
name = "chicken crate"
starts_with = list(/mob/living/simple_animal/chick = 5)
starts_with = list(/mob/living/simple_mob/animal/passive/chick = 5)
@@ -0,0 +1,106 @@
/obj/structure/vehiclecage
name = "vehicle cage"
desc = "A large metal lattice that seems to exist solely to annoy consumers."
icon = 'icons/obj/storage.dmi'
icon_state = "vehicle_cage"
density = 1
var/obj/vehicle/my_vehicle
var/my_vehicle_type
var/paint_color = "#666666"
/obj/structure/vehiclecage/examine(mob/user)
..()
if(my_vehicle)
to_chat(user, "<span class='notice'>It seems to contain \the [my_vehicle].</span>")
/obj/structure/vehiclecage/Initialize()
. = ..()
if(my_vehicle_type)
my_vehicle = new my_vehicle_type(src)
for(var/obj/I in get_turf(src))
if(I.density || I.anchored || I == src || !I.simulated || !istype(I, my_vehicle_type))
continue
load_vehicle(I)
update_icon()
/obj/structure/vehiclecage/attack_hand(mob/user as mob)
to_chat(user, "<span class='notice'>You need a wrench to take this apart!</span>")
return
/obj/structure/vehiclecage/attackby(obj/item/weapon/W as obj, mob/user as mob)
var/turf/T = get_turf(src)
if(!T)
to_chat(user, "<span class='notice'>You can't open this here!</span>")
if(W.is_wrench() && do_after(user, 60 * W.toolspeed, src))
playsound(loc, W.usesound, 50, 1)
disassemble(W, user)
user.visible_message("<span class='notice'>[user] begins loosening \the [src]'s bolts.</span>")
if(W.is_wirecutter() && do_after(user, 70 * W.toolspeed, src))
playsound(loc, W.usesound, 50, 1)
disassemble(W, user)
user.visible_message("<span class='notice'>[user] begins cutting \the [src]'s bolts.</span>")
else
return attack_hand(user)
/obj/structure/vehiclecage/update_icon()
..()
overlays.Cut()
underlays.Cut()
var/image/framepaint = new(icon = 'icons/obj/storage.dmi', icon_state = "[initial(icon_state)]_a", layer = MOB_LAYER + 1.1)
framepaint.plane = MOB_PLANE
framepaint.color = paint_color
overlays += framepaint
for(var/obj/vehicle/V in src.contents)
var/image/showcase = new(V)
showcase.layer = src.layer - 0.1
underlays += showcase
/obj/structure/vehiclecage/MouseDrop_T(var/atom/movable/C, mob/user as mob)
if(user && (user.buckled || user.stat || user.restrained() || !Adjacent(user) || !user.Adjacent(C)))
return
var/obj/vehicle/V
if(istype(C, /obj/vehicle))
V = C
if(!V)
return
if(!my_vehicle)
load_vehicle(V, user)
/obj/structure/vehiclecage/proc/load_vehicle(var/obj/vehicle/V, mob/user as mob)
if(user)
user.visible_message("<span class='notice'>[user] loads \the [V] into \the [src].</span>", \
"<span class='notice'>You load \the [V] into \the [src].</span>", \
"<span class='notice'>You hear creaking metal.</span>")
V.forceMove(src)
paint_color = V.paint_color
update_icon()
/obj/structure/vehiclecage/proc/disassemble(obj/item/weapon/W as obj, mob/user as mob)
var/turf/T = get_turf(src)
new /obj/item/stack/material/steel(src.loc, 5)
for(var/atom/movable/AM in contents)
if(AM.simulated)
AM.forceMove(T)
my_vehicle = null
user.visible_message("<span class='notice'>[user] release \the [src].</span>", \
"<span class='notice'>You finally release \the [src].</span>", \
"<span class='notice'>You hear creaking metal.</span>")
qdel(src)
/obj/structure/vehiclecage/spacebike
my_vehicle_type = /obj/vehicle/bike/random
/obj/structure/vehiclecage/quadbike
my_vehicle_type = /obj/vehicle/train/engine/quadbike/random
/obj/structure/vehiclecage/quadtrailer
my_vehicle_type = /obj/vehicle/train/trolley/trailer/random
+2 -2
View File
@@ -304,7 +304,7 @@
light_power = 0.6
light_color = "#FF6633"
/obj/structure/flora/sif/subterranean/initialize()
/obj/structure/flora/sif/subterranean/Initialize()
icon_state = "[initial(icon_state)][rand(1,2)]"
. = ..()
@@ -313,6 +313,6 @@
desc = "This is a mysterious looking plant. They kind of look like eyeballs. Creepy."
icon_state = "eyeplant"
/obj/structure/flora/sif/eyes/initialize()
/obj/structure/flora/sif/eyes/Initialize()
icon_state = "[initial(icon_state)][rand(1,3)]"
. = ..()
@@ -59,7 +59,7 @@
var/delay_to_self_open = 10 MINUTES // How long to wait for first attempt. Note that the timer by default starts when the pod is created.
var/delay_to_try_again = 20 MINUTES // How long to wait if first attempt fails. Set to 0 to never try again.
/obj/structure/ghost_pod/automatic/initialize()
/obj/structure/ghost_pod/automatic/Initialize()
. = ..()
spawn(delay_to_self_open)
if(src)
@@ -15,7 +15,7 @@
/obj/structure/ghost_pod/manual/corgi/create_occupant(var/mob/M)
lightning_strike(get_turf(src), cosmetic = TRUE)
density = FALSE
var/mob/living/simple_animal/corgi/R = new(get_turf(src))
var/mob/living/simple_mob/animal/passive/dog/corgi/R = new(get_turf(src))
if(M.mind)
M.mind.transfer_to(R)
to_chat(M, "<span class='notice'>You are a <b>Corgi</b>! Woof!</span>")
@@ -47,4 +47,4 @@
R.ghost_inhabit(M)
visible_message("<span class='warning'>The blade shines brightly for a brief moment as [usr] pulls it out of the stone!</span>")
log_and_message_admins("successfully acquired a cursed sword.")
..()
..()
+58 -7
View File
@@ -25,12 +25,12 @@
/obj/structure/girder/Destroy()
if(girder_material.products_need_process())
processing_objects -= src
STOP_PROCESSING(SSobj, src)
. = ..()
/obj/structure/girder/process()
if(!radiate())
processing_objects -= src
STOP_PROCESSING(SSobj, src)
return
/obj/structure/girder/proc/radiate()
@@ -53,9 +53,9 @@
if(applies_material_colour)
color = girder_material.icon_colour
if(girder_material.products_need_process()) //Am I radioactive or some other? Process me!
processing_objects |= src
else if(src in processing_objects) //If I happened to be radioactive or s.o. previously, and am not now, stop processing.
processing_objects -= src
START_PROCESSING(SSobj, src)
else if(is_processing) //If I happened to be radioactive or s.o. previously, and am not now, stop processing.
STOP_PROCESSING(SSobj, src)
/obj/structure/girder/get_material()
return girder_material
@@ -83,8 +83,8 @@
health = (displaced_health - round(current_damage / 4))
cover = 25
/obj/structure/girder/attack_generic(var/mob/user, var/damage, var/attack_message = "smashes apart", var/wallbreaker)
if(!damage || !wallbreaker)
/obj/structure/girder/attack_generic(var/mob/user, var/damage, var/attack_message = "smashes apart")
if(damage < STRUCTURE_MIN_DAMAGE_THRESHOLD)
return 0
user.do_attack_animation(src)
visible_message("<span class='danger'>[user] [attack_message] the [src]!</span>")
@@ -353,3 +353,54 @@
to_chat(user, "<span class='notice'>You drill through the girder!</span>")
new /obj/effect/decal/remains/human(get_turf(src))
dismantle()
/obj/structure/girder/rcd_values(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
var/turf/simulated/T = get_turf(src)
if(!istype(T) || T.density)
return FALSE
switch(passed_mode)
if(RCD_FLOORWALL)
// Finishing a wall costs two sheets.
var/cost = RCD_SHEETS_PER_MATTER_UNIT * 2
// Rwalls cost three to finish.
if(the_rcd.make_rwalls)
cost += RCD_SHEETS_PER_MATTER_UNIT * 1
return list(
RCD_VALUE_MODE = RCD_FLOORWALL,
RCD_VALUE_DELAY = 2 SECONDS,
RCD_VALUE_COST = cost
)
if(RCD_DECONSTRUCT)
return list(
RCD_VALUE_MODE = RCD_DECONSTRUCT,
RCD_VALUE_DELAY = 2 SECONDS,
RCD_VALUE_COST = RCD_SHEETS_PER_MATTER_UNIT * 5
)
return FALSE
/obj/structure/girder/rcd_act(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
var/turf/simulated/T = get_turf(src)
if(!istype(T) || T.density) // Should stop future bugs of people bringing girders to centcom and RCDing them, or somehow putting a girder on a durasteel wall and deconning it.
return FALSE
switch(passed_mode)
if(RCD_FLOORWALL)
to_chat(user, span("notice", "You finish a wall."))
// This is mostly the same as using on a floor. The girder's material is preserved, however.
T.ChangeTurf(/turf/simulated/wall)
var/turf/simulated/wall/new_T = get_turf(src) // Ref to the wall we just built.
// Apparently set_material(...) for walls requires refs to the material singletons and not strings.
// This is different from how other material objects with their own set_material(...) do it, but whatever.
var/material/M = name_to_material[the_rcd.material_to_use]
new_T.set_material(M, the_rcd.make_rwalls ? M : null, girder_material)
new_T.add_hiddenprint(user)
qdel(src)
return TRUE
if(RCD_DECONSTRUCT)
to_chat(user, span("notice", "You deconstruct \the [src]."))
qdel(src)
return TRUE
+1 -1
View File
@@ -126,7 +126,7 @@
src.set_dir(turn(src.dir, 90))
return
else
if(istype(usr,/mob/living/simple_animal/mouse))
if(ismouse(usr))
return
if(!usr || !isturf(usr.loc))
return
+40 -3
View File
@@ -93,10 +93,12 @@
src.health -= damage*0.2
spawn(0) healthcheck() //spawn to make sure we return properly if the grille is deleted
/obj/structure/grille/attackby(obj/item/weapon/W as obj, mob/user as mob)
/obj/structure/grille/attackby(obj/item/W as obj, mob/user as mob)
if(!istype(W))
return
if(W.is_wirecutter())
if(istype(W, /obj/item/weapon/rcd)) // To stop us from hitting the grille when building windows, because grilles don't let parent handle it properly.
return FALSE
else if(W.is_wirecutter())
if(!shock(user, 100))
playsound(src, W.usesound, 100, 1)
new /obj/item/stack/rods(get_turf(src), destroyed ? 1 : 2)
@@ -109,7 +111,7 @@
"<span class='notice'>You have [anchored ? "fastened the grille to" : "unfastened the grille from"] the floor.</span>")
return
//window placing begin //TODO CONVERT PROPERLY TO MATERIAL DATUM
//window placing begin //TODO CONVERT PROPERLY TO MATERIAL DATUM
else if(istype(W,/obj/item/stack/material))
var/obj/item/stack/material/ST = W
if(!ST.material.created_window)
@@ -252,3 +254,38 @@
/obj/structure/grille/broken/rustic
icon_state = "grillerustic-b"
/obj/structure/grille/rcd_values(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
switch(passed_mode)
if(RCD_WINDOWGRILLE)
// A full tile window costs 4 glass sheets.
return list(
RCD_VALUE_MODE = RCD_WINDOWGRILLE,
RCD_VALUE_DELAY = 2 SECONDS,
RCD_VALUE_COST = RCD_SHEETS_PER_MATTER_UNIT * 4
)
if(RCD_DECONSTRUCT)
return list(
RCD_VALUE_MODE = RCD_DECONSTRUCT,
RCD_VALUE_DELAY = 2 SECONDS,
RCD_VALUE_COST = RCD_SHEETS_PER_MATTER_UNIT * 2
)
return FALSE
/obj/structure/grille/rcd_act(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
switch(passed_mode)
if(RCD_DECONSTRUCT)
to_chat(user, span("notice", "You deconstruct \the [src]."))
qdel(src)
return TRUE
if(RCD_WINDOWGRILLE)
if(locate(/obj/structure/window) in loc)
return FALSE
to_chat(user, span("notice", "You construct a window."))
var/obj/structure/window/WD = new the_rcd.window_type(loc)
WD.anchored = TRUE
return TRUE
return FALSE
+2 -2
View File
@@ -17,7 +17,7 @@
"plant-13"
)
/obj/machinery/holoplant/initialize()
/obj/machinery/holoplant/Initialize()
. = ..()
activate()
@@ -101,5 +101,5 @@
/obj/machinery/holoplant/shipped
anchored = FALSE
/obj/machinery/holoplant/shipped/initialize()
/obj/machinery/holoplant/shipped/Initialize()
. = ..()
+1 -1
View File
@@ -9,7 +9,7 @@
plane = PLATING_PLANE
// flags = CONDUCT
/obj/structure/lattice/initialize()
/obj/structure/lattice/Initialize()
. = ..()
if(!(istype(src.loc, /turf/space) || istype(src.loc, /turf/simulated/open) || istype(src.loc, /turf/simulated/mineral)))
+45 -2
View File
@@ -115,7 +115,7 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh
var/path = pick(rare_loot)
return new path(src)
/obj/structure/loot_pile/initialize()
/obj/structure/loot_pile/Initialize()
if(icon_states_to_use && icon_states_to_use.len)
icon_state = pick(icon_states_to_use)
. = ..()
@@ -574,6 +574,7 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh
icon = 'icons/mecha/mecha.dmi'
icon_state = "engineering_pod-broken"
density = TRUE
anchored = FALSE // In case a dead mecha-mob dies in a bad spot.
chance_uncommon = 20
chance_rare = 10
@@ -615,7 +616,7 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh
/obj/structure/loot_pile/mecha/ripley
name = "ripley wreckage"
desc = "The ruins of some unfortunate ripley. Perhaps something is salvageable."
icon_states_to_use = list("ripley-broken", "firefighter-broken", "ripley-broken-old")
icon_state = "ripley-broken"
common_loot = list(
/obj/random/tool,
@@ -649,6 +650,12 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh
/obj/item/mecha_parts/mecha_equipment/weapon/energy/flamer/rigged
)
/obj/structure/loot_pile/mecha/ripley/firefighter
icon_state = "firefighter-broken"
/obj/structure/loot_pile/mecha/ripley/random_sprite
icon_states_to_use = list("ripley-broken", "firefighter-broken", "ripley-broken-old")
//Death-Ripley, same common, but more combat-exosuit-based
/obj/structure/loot_pile/mecha/deathripley
name = "strange ripley wreckage"
@@ -719,6 +726,14 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh
/obj/item/mecha_parts/mecha_equipment/shocker
)
/obj/structure/loot_pile/mecha/odysseus/murdysseus
icon_state = "murdysseus-broken"
/obj/structure/loot_pile/mecha/hoverpod
name = "hoverpod wreckage"
desc = "The ruins of some unfortunate hoverpod. Perhaps something is salvageable."
icon_state = "engineering_pod"
/obj/structure/loot_pile/mecha/gygax
name = "gygax wreckage"
desc = "The ruins of some unfortunate gygax. Perhaps something is salvageable."
@@ -759,6 +774,18 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh
/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy
)
/obj/structure/loot_pile/mecha/gygax/dark
icon_state = "darkgygax-broken"
// Todo: Better loot.
/obj/structure/loot_pile/mecha/gygax/dark/adv
icon_state = "darkgygax_adv-broken"
icon_scale = 1.5
pixel_y = 8
/obj/structure/loot_pile/mecha/gygax/medgax
icon_state = "medgax-broken"
/obj/structure/loot_pile/mecha/durand
name = "durand wreckage"
desc = "The ruins of some unfortunate durand. Perhaps something is salvageable."
@@ -799,6 +826,22 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh
/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy
)
/obj/structure/loot_pile/mecha/marauder
name = "marauder wreckage"
desc = "The ruins of some unfortunate marauder. Perhaps something is salvagable."
icon_state = "marauder-broken"
// Todo: Better loot.
/obj/structure/loot_pile/mecha/marauder/seraph
name = "seraph wreckage"
desc = "The ruins of some unfortunate seraph. Perhaps something is salvagable."
icon_state = "seraph-broken"
/obj/structure/loot_pile/mecha/marauder/mauler
name = "mauler wreckage"
desc = "The ruins of some unfortunate mauler. Perhaps something is salvagable."
icon_state = "mauler-broken"
/obj/structure/loot_pile/mecha/phazon
name = "phazon wreckage"
desc = "The ruins of some unfortunate phazon. Perhaps something is salvageable."
+286 -368
View File
@@ -1,253 +1,110 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32
#define MUSICIAN_HEARCHECK_MINDELAY 4
#define INSTRUMENT_MAX_LINE_LENGTH 300
#define INSTRUMENT_MAX_LINE_NUMBER 50
/datum/song
var/name = "Untitled"
var/list/lines = new()
var/tempo = 5
var/tempo = 5 // delay between notes
/obj/structure/device/piano
name = "space minimoog"
icon = 'icons/obj/musician.dmi'
icon_state = "minimoog"
anchored = 1
density = 1
var/datum/song/song
var/playing = 0
var/help = 0
var/edit = 1
var/repeat = 0
var/playing = 0 // if we're playing
var/help = 0 // if help is open
var/edit = 1 // if we're in editing mode
var/repeat = 0 // number of times remaining to repeat
var/max_repeats = 10 // maximum times we can repeat
/obj/structure/device/piano/New()
if(prob(50))
name = "space minimoog"
desc = "This is a minimoog, like a space piano, but more spacey!"
icon_state = "minimoog"
var/instrumentDir = "piano" // the folder with the sounds
var/instrumentExt = "ogg" // the file extension
var/obj/instrumentObj = null // the associated obj playing the sound
var/last_hearcheck = 0
var/list/hearing_mobs
/datum/song/New(dir, obj, ext = "ogg")
instrumentDir = dir
instrumentObj = obj
instrumentExt = ext
/datum/song/Destroy()
instrumentObj = null
return ..()
// note is a number from 1-7 for A-G
// acc is either "b", "n", or "#"
// oct is 1-8 (or 9 for C)
/datum/song/proc/playnote(note, acc as text, oct)
// handle accidental -> B<>C of E<>F
if(acc == "b" && (note == 3 || note == 6)) // C or F
if(note == 3)
oct--
note--
acc = "n"
else if(acc == "#" && (note == 2 || note == 5)) // B or E
if(note == 2)
oct++
note++
acc = "n"
else if(acc == "#" && (note == 7)) //G#
note = 1
acc = "b"
else if(acc == "#") // mass convert all sharps to flats, octave jump already handled
acc = "b"
note++
// check octave, C is allowed to go to 9
if(oct < 1 || (note == 3 ? oct > 9 : oct > 8))
return
// now generate name
var/soundfile = "sound/instruments/[instrumentDir]/[ascii2text(note+64)][acc][oct].[instrumentExt]"
soundfile = file(soundfile)
// make sure the note exists
if(!fexists(soundfile))
return
// and play
var/turf/source = get_turf(instrumentObj)
if((world.time - MUSICIAN_HEARCHECK_MINDELAY) > last_hearcheck)
LAZYCLEARLIST(hearing_mobs)
for(var/mob/M in hearers(15, source))
if(!M.client || !(M.is_preference_enabled(/datum/client_preference/instrument_toggle)))
continue
LAZYSET(hearing_mobs, M, TRUE)
last_hearcheck = world.time
var/sound/music_played = sound(soundfile)
for(var/i in hearing_mobs)
var/mob/M = i
M.playsound_local(source, null, 100, falloff = 5, S = music_played)
/datum/song/proc/updateDialog(mob/user)
instrumentObj.updateDialog() // assumes it's an object in world, override if otherwise
/datum/song/proc/shouldStopPlaying(mob/user)
if(instrumentObj)
if(!instrumentObj.Adjacent(user) || user.stat)
return 1
return !instrumentObj.anchored // add special cases to stop in subclasses
else
name = "space piano"
desc = "This is a space piano, like a regular piano, but always in tune! Even if the musician isn't."
icon_state = "piano"
return 1
/obj/structure/device/piano/verb/rotate()
set name = "Rotate Piano"
set category = "Object"
set src in oview(1)
if(istype(usr,/mob/living/simple_animal/mouse))
return
else if(!usr || !isturf(usr.loc))
return
else if(usr.stat || usr.restrained())
return
else if (istype(usr,/mob/observer/ghost) && !config.ghost_interaction)
return
else
src.set_dir(turn(src.dir, 90))
return
/obj/structure/device/piano/proc/playnote(var/note as text)
//world << "Note: [note]"
var/soundfile
/*BYOND loads resource files at compile time if they are ''. This means you can't really manipulate them dynamically.
Tried doing it dynamically at first but its more trouble than its worth. Would have saved many lines tho.*/
switch(note)
if("Cn1") soundfile = 'sound/piano/Cn1.ogg'
if("C#1") soundfile = 'sound/piano/C#1.ogg'
if("Db1") soundfile = 'sound/piano/Db1.ogg'
if("Dn1") soundfile = 'sound/piano/Dn1.ogg'
if("D#1") soundfile = 'sound/piano/D#1.ogg'
if("Eb1") soundfile = 'sound/piano/Eb1.ogg'
if("En1") soundfile = 'sound/piano/En1.ogg'
if("E#1") soundfile = 'sound/piano/E#1.ogg'
if("Fb1") soundfile = 'sound/piano/Fb1.ogg'
if("Fn1") soundfile = 'sound/piano/Fn1.ogg'
if("F#1") soundfile = 'sound/piano/F#1.ogg'
if("Gb1") soundfile = 'sound/piano/Gb1.ogg'
if("Gn1") soundfile = 'sound/piano/Gn1.ogg'
if("G#1") soundfile = 'sound/piano/G#1.ogg'
if("Ab1") soundfile = 'sound/piano/Ab1.ogg'
if("An1") soundfile = 'sound/piano/An1.ogg'
if("A#1") soundfile = 'sound/piano/A#1.ogg'
if("Bb1") soundfile = 'sound/piano/Bb1.ogg'
if("Bn1") soundfile = 'sound/piano/Bn1.ogg'
if("B#1") soundfile = 'sound/piano/B#1.ogg'
if("Cb2") soundfile = 'sound/piano/Cb2.ogg'
if("Cn2") soundfile = 'sound/piano/Cn2.ogg'
if("C#2") soundfile = 'sound/piano/C#2.ogg'
if("Db2") soundfile = 'sound/piano/Db2.ogg'
if("Dn2") soundfile = 'sound/piano/Dn2.ogg'
if("D#2") soundfile = 'sound/piano/D#2.ogg'
if("Eb2") soundfile = 'sound/piano/Eb2.ogg'
if("En2") soundfile = 'sound/piano/En2.ogg'
if("E#2") soundfile = 'sound/piano/E#2.ogg'
if("Fb2") soundfile = 'sound/piano/Fb2.ogg'
if("Fn2") soundfile = 'sound/piano/Fn2.ogg'
if("F#2") soundfile = 'sound/piano/F#2.ogg'
if("Gb2") soundfile = 'sound/piano/Gb2.ogg'
if("Gn2") soundfile = 'sound/piano/Gn2.ogg'
if("G#2") soundfile = 'sound/piano/G#2.ogg'
if("Ab2") soundfile = 'sound/piano/Ab2.ogg'
if("An2") soundfile = 'sound/piano/An2.ogg'
if("A#2") soundfile = 'sound/piano/A#2.ogg'
if("Bb2") soundfile = 'sound/piano/Bb2.ogg'
if("Bn2") soundfile = 'sound/piano/Bn2.ogg'
if("B#2") soundfile = 'sound/piano/B#2.ogg'
if("Cb3") soundfile = 'sound/piano/Cb3.ogg'
if("Cn3") soundfile = 'sound/piano/Cn3.ogg'
if("C#3") soundfile = 'sound/piano/C#3.ogg'
if("Db3") soundfile = 'sound/piano/Db3.ogg'
if("Dn3") soundfile = 'sound/piano/Dn3.ogg'
if("D#3") soundfile = 'sound/piano/D#3.ogg'
if("Eb3") soundfile = 'sound/piano/Eb3.ogg'
if("En3") soundfile = 'sound/piano/En3.ogg'
if("E#3") soundfile = 'sound/piano/E#3.ogg'
if("Fb3") soundfile = 'sound/piano/Fb3.ogg'
if("Fn3") soundfile = 'sound/piano/Fn3.ogg'
if("F#3") soundfile = 'sound/piano/F#3.ogg'
if("Gb3") soundfile = 'sound/piano/Gb3.ogg'
if("Gn3") soundfile = 'sound/piano/Gn3.ogg'
if("G#3") soundfile = 'sound/piano/G#3.ogg'
if("Ab3") soundfile = 'sound/piano/Ab3.ogg'
if("An3") soundfile = 'sound/piano/An3.ogg'
if("A#3") soundfile = 'sound/piano/A#3.ogg'
if("Bb3") soundfile = 'sound/piano/Bb3.ogg'
if("Bn3") soundfile = 'sound/piano/Bn3.ogg'
if("B#3") soundfile = 'sound/piano/B#3.ogg'
if("Cb4") soundfile = 'sound/piano/Cb4.ogg'
if("Cn4") soundfile = 'sound/piano/Cn4.ogg'
if("C#4") soundfile = 'sound/piano/C#4.ogg'
if("Db4") soundfile = 'sound/piano/Db4.ogg'
if("Dn4") soundfile = 'sound/piano/Dn4.ogg'
if("D#4") soundfile = 'sound/piano/D#4.ogg'
if("Eb4") soundfile = 'sound/piano/Eb4.ogg'
if("En4") soundfile = 'sound/piano/En4.ogg'
if("E#4") soundfile = 'sound/piano/E#4.ogg'
if("Fb4") soundfile = 'sound/piano/Fb4.ogg'
if("Fn4") soundfile = 'sound/piano/Fn4.ogg'
if("F#4") soundfile = 'sound/piano/F#4.ogg'
if("Gb4") soundfile = 'sound/piano/Gb4.ogg'
if("Gn4") soundfile = 'sound/piano/Gn4.ogg'
if("G#4") soundfile = 'sound/piano/G#4.ogg'
if("Ab4") soundfile = 'sound/piano/Ab4.ogg'
if("An4") soundfile = 'sound/piano/An4.ogg'
if("A#4") soundfile = 'sound/piano/A#4.ogg'
if("Bb4") soundfile = 'sound/piano/Bb4.ogg'
if("Bn4") soundfile = 'sound/piano/Bn4.ogg'
if("B#4") soundfile = 'sound/piano/B#4.ogg'
if("Cb5") soundfile = 'sound/piano/Cb5.ogg'
if("Cn5") soundfile = 'sound/piano/Cn5.ogg'
if("C#5") soundfile = 'sound/piano/C#5.ogg'
if("Db5") soundfile = 'sound/piano/Db5.ogg'
if("Dn5") soundfile = 'sound/piano/Dn5.ogg'
if("D#5") soundfile = 'sound/piano/D#5.ogg'
if("Eb5") soundfile = 'sound/piano/Eb5.ogg'
if("En5") soundfile = 'sound/piano/En5.ogg'
if("E#5") soundfile = 'sound/piano/E#5.ogg'
if("Fb5") soundfile = 'sound/piano/Fb5.ogg'
if("Fn5") soundfile = 'sound/piano/Fn5.ogg'
if("F#5") soundfile = 'sound/piano/F#5.ogg'
if("Gb5") soundfile = 'sound/piano/Gb5.ogg'
if("Gn5") soundfile = 'sound/piano/Gn5.ogg'
if("G#5") soundfile = 'sound/piano/G#5.ogg'
if("Ab5") soundfile = 'sound/piano/Ab5.ogg'
if("An5") soundfile = 'sound/piano/An5.ogg'
if("A#5") soundfile = 'sound/piano/A#5.ogg'
if("Bb5") soundfile = 'sound/piano/Bb5.ogg'
if("Bn5") soundfile = 'sound/piano/Bn5.ogg'
if("B#5") soundfile = 'sound/piano/B#5.ogg'
if("Cb6") soundfile = 'sound/piano/Cb6.ogg'
if("Cn6") soundfile = 'sound/piano/Cn6.ogg'
if("C#6") soundfile = 'sound/piano/C#6.ogg'
if("Db6") soundfile = 'sound/piano/Db6.ogg'
if("Dn6") soundfile = 'sound/piano/Dn6.ogg'
if("D#6") soundfile = 'sound/piano/D#6.ogg'
if("Eb6") soundfile = 'sound/piano/Eb6.ogg'
if("En6") soundfile = 'sound/piano/En6.ogg'
if("E#6") soundfile = 'sound/piano/E#6.ogg'
if("Fb6") soundfile = 'sound/piano/Fb6.ogg'
if("Fn6") soundfile = 'sound/piano/Fn6.ogg'
if("F#6") soundfile = 'sound/piano/F#6.ogg'
if("Gb6") soundfile = 'sound/piano/Gb6.ogg'
if("Gn6") soundfile = 'sound/piano/Gn6.ogg'
if("G#6") soundfile = 'sound/piano/G#6.ogg'
if("Ab6") soundfile = 'sound/piano/Ab6.ogg'
if("An6") soundfile = 'sound/piano/An6.ogg'
if("A#6") soundfile = 'sound/piano/A#6.ogg'
if("Bb6") soundfile = 'sound/piano/Bb6.ogg'
if("Bn6") soundfile = 'sound/piano/Bn6.ogg'
if("B#6") soundfile = 'sound/piano/B#6.ogg'
if("Cb7") soundfile = 'sound/piano/Cb7.ogg'
if("Cn7") soundfile = 'sound/piano/Cn7.ogg'
if("C#7") soundfile = 'sound/piano/C#7.ogg'
if("Db7") soundfile = 'sound/piano/Db7.ogg'
if("Dn7") soundfile = 'sound/piano/Dn7.ogg'
if("D#7") soundfile = 'sound/piano/D#7.ogg'
if("Eb7") soundfile = 'sound/piano/Eb7.ogg'
if("En7") soundfile = 'sound/piano/En7.ogg'
if("E#7") soundfile = 'sound/piano/E#7.ogg'
if("Fb7") soundfile = 'sound/piano/Fb7.ogg'
if("Fn7") soundfile = 'sound/piano/Fn7.ogg'
if("F#7") soundfile = 'sound/piano/F#7.ogg'
if("Gb7") soundfile = 'sound/piano/Gb7.ogg'
if("Gn7") soundfile = 'sound/piano/Gn7.ogg'
if("G#7") soundfile = 'sound/piano/G#7.ogg'
if("Ab7") soundfile = 'sound/piano/Ab7.ogg'
if("An7") soundfile = 'sound/piano/An7.ogg'
if("A#7") soundfile = 'sound/piano/A#7.ogg'
if("Bb7") soundfile = 'sound/piano/Bb7.ogg'
if("Bn7") soundfile = 'sound/piano/Bn7.ogg'
if("B#7") soundfile = 'sound/piano/B#7.ogg'
if("Cb8") soundfile = 'sound/piano/Cb8.ogg'
if("Cn8") soundfile = 'sound/piano/Cn8.ogg'
if("C#8") soundfile = 'sound/piano/C#8.ogg'
if("Db8") soundfile = 'sound/piano/Db8.ogg'
if("Dn8") soundfile = 'sound/piano/Dn8.ogg'
if("D#8") soundfile = 'sound/piano/D#8.ogg'
if("Eb8") soundfile = 'sound/piano/Eb8.ogg'
if("En8") soundfile = 'sound/piano/En8.ogg'
if("E#8") soundfile = 'sound/piano/E#8.ogg'
if("Fb8") soundfile = 'sound/piano/Fb8.ogg'
if("Fn8") soundfile = 'sound/piano/Fn8.ogg'
if("F#8") soundfile = 'sound/piano/F#8.ogg'
if("Gb8") soundfile = 'sound/piano/Gb8.ogg'
if("Gn8") soundfile = 'sound/piano/Gn8.ogg'
if("G#8") soundfile = 'sound/piano/G#8.ogg'
if("Ab8") soundfile = 'sound/piano/Ab8.ogg'
if("An8") soundfile = 'sound/piano/An8.ogg'
if("A#8") soundfile = 'sound/piano/A#8.ogg'
if("Bb8") soundfile = 'sound/piano/Bb8.ogg'
if("Bn8") soundfile = 'sound/piano/Bn8.ogg'
if("B#8") soundfile = 'sound/piano/B#8.ogg'
if("Cb9") soundfile = 'sound/piano/Cb9.ogg'
if("Cn9") soundfile = 'sound/piano/Cn9.ogg'
else return
//hearers(15, src) << sound(soundfile)
var/turf/source = get_turf(src)
for(var/mob/M in hearers(15, source))
M.playsound_local(source, file(soundfile), 100, falloff = 5)
/obj/structure/device/piano/proc/playsong()
do
/datum/song/proc/playsong(mob/user)
while(repeat >= 0)
var/cur_oct[7]
var/cur_acc[7]
for(var/i = 1 to 7)
cur_oct[i] = "3"
cur_oct[i] = 3
cur_acc[i] = "n"
for(var/line in song.lines)
//world << line
for(var/line in lines)
for(var/beat in splittext(lowertext(line), ","))
//world << "beat: [beat]"
var/list/notes = splittext(beat, "/")
for(var/note in splittext(notes[1], "-"))
//world << "note: [note]"
if(!playing || !anchored)//If the piano is playing, or is loose
if(!playing || shouldStopPlaying(user))//If the instrument is playing, or special case
playing = 0
return
if(lentext(note) == 0)
continue
//world << "Parse: [copytext(note,1,2)]"
var/cur_note = text2ascii(note) - 96
if(cur_note < 1 || cur_note > 7)
continue
@@ -259,49 +116,47 @@
else if(ni == "s")
cur_acc[cur_note] = "#" // so shift is never required
else
cur_oct[cur_note] = ni
playnote(uppertext(copytext(note,1,2)) + cur_acc[cur_note] + cur_oct[cur_note])
cur_oct[cur_note] = text2num(ni)
playnote(cur_note, cur_acc[cur_note], cur_oct[cur_note])
if(notes.len >= 2 && text2num(notes[2]))
sleep(song.tempo / text2num(notes[2]))
sleep(sanitize_tempo(tempo / text2num(notes[2])))
else
sleep(song.tempo)
if(repeat > 0)
repeat-- //Infinite loops are baaaad.
while(repeat > 0)
sleep(tempo)
repeat--
playing = 0
updateUsrDialog()
repeat = 0
updateDialog(user)
/obj/structure/device/piano/attack_hand(var/mob/user as mob)
if(!anchored)
return
usr.machine = src
var/dat = "<HEAD><TITLE>Piano</TITLE></HEAD><BODY>"
if(song)
if(song.lines.len > 0 && !(playing))
dat += "<A href='?src=\ref[src];play=1'>Play Song</A><BR><BR>"
dat += "<A href='?src=\ref[src];repeat=1'>Repeat Song: [repeat] times.</A><BR><BR>"
if(playing)
dat += "<A href='?src=\ref[src];stop=1'>Stop Playing</A><BR>"
dat += "Repeats left: [repeat].<BR><BR>"
/datum/song/proc/interact(mob/user)
var/dat = ""
if(lines.len > 0)
dat += "<H3>Playback</H3>"
if(!playing)
dat += {"<A href='?src=\ref[src];play=1'>Play</A> <SPAN CLASS='linkOn'>Stop</SPAN><BR><BR>
Repeat Song:
[repeat > 0 ? "<A href='?src=\ref[src];repeat=-10'>-</A><A href='?src=\ref[src];repeat=-1'>-</A>" : "<SPAN CLASS='linkOff'>-</SPAN><SPAN CLASS='linkOff'>-</SPAN>"]
[repeat] times
[repeat < max_repeats ? "<A href='?src=\ref[src];repeat=1'>+</A><A href='?src=\ref[src];repeat=10'>+</A>" : "<SPAN CLASS='linkOff'>+</SPAN><SPAN CLASS='linkOff'>+</SPAN>"]
<BR>"}
else
dat += {"<SPAN CLASS='linkOn'>Play</SPAN> <A href='?src=\ref[src];stop=1'>Stop</A><BR>
Repeats left: <B>[repeat]</B><BR>"}
if(!edit)
dat += "<A href='?src=\ref[src];edit=2'>Show Editor</A><BR><BR>"
dat += "<BR><B><A href='?src=\ref[src];edit=2'>Show Editor</A></B><BR>"
else
dat += "<A href='?src=\ref[src];edit=1'>Hide Editor</A><BR>"
dat += "<A href='?src=\ref[src];newsong=1'>Start a New Song</A><BR>"
dat += "<A href='?src=\ref[src];import=1'>Import a Song</A><BR><BR>"
if(song)
var/calctempo = (10/song.tempo)*60
dat += "Tempo : <A href='?src=\ref[src];tempo=10'>-</A><A href='?src=\ref[src];tempo=1'>-</A> [calctempo] BPM <A href='?src=\ref[src];tempo=-1'>+</A><A href='?src=\ref[src];tempo=-10'>+</A><BR><BR>"
var/linecount = 0
for(var/line in song.lines)
linecount += 1
dat += "Line [linecount]: [line] <A href='?src=\ref[src];deleteline=[linecount]'>Delete Line</A> <A href='?src=\ref[src];modifyline=[linecount]'>Modify Line</A><BR>"
dat += "<A href='?src=\ref[src];newline=1'>Add Line</A><BR><BR>"
var/bpm = round(600 / tempo)
dat += {"<H3>Editing</H3>
<B><A href='?src=\ref[src];edit=1'>Hide Editor</A></B>
<A href='?src=\ref[src];newsong=1'>Start a New Song</A>
<A href='?src=\ref[src];import=1'>Import a Song</A><BR><BR>
Tempo: <A href='?src=\ref[src];tempo=[world.tick_lag]'>-</A> [bpm] BPM <A href='?src=\ref[src];tempo=-[world.tick_lag]'>+</A><BR><BR>"}
var/linecount = 0
for(var/line in lines)
linecount += 1
dat += "Line [linecount]: <A href='?src=\ref[src];modifyline=[linecount]'>Edit</A> <A href='?src=\ref[src];deleteline=[linecount]'>X</A> [line]<BR>"
dat += "<A href='?src=\ref[src];newline=1'>Add Line</A><BR><BR>"
if(help)
dat += "<A href='?src=\ref[src];help=1'>Hide Help</A><BR>"
dat += {"
dat += {"<B><A href='?src=\ref[src];help=1'>Hide Help</A></B><BR>
Lines are a series of chords, separated by commas (,), each with notes seperated by hyphens (-).<br>
Every note in a chord will play together, with chord timed by the tempo.<br>
<br>
@@ -313,120 +168,183 @@
A pause may be denoted by an empty chord: <i>C,E,,C,G</i><br>
To make a chord be a different time, end it with /x, where the chord length will be length<br>
defined by tempo / x: <i>C,G/2,E/4</i><br>
Combined, an example is: <i>E-E4/4,/2,G#/8,B/8,E3-E4/4</i>
Combined, an example is: <i>E-E4/4,F#/2,G#/8,B/8,E3-E4/4</i>
<br>
Lines may be up to 50 characters.<br>
A song may only contain up to 50 lines.<br>
"}
else
dat += "<A href='?src=\ref[src];help=2'>Show Help</A><BR>"
dat += "</BODY></HTML>"
user << browse(dat, "window=piano;size=700x300")
onclose(user, "piano")
dat += "<B><A href='?src=\ref[src];help=2'>Show Help</A></B><BR>"
var/datum/browser/popup = new(user, "instrument", instrumentObj.name, 700, 500)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(instrumentObj.icon, instrumentObj.icon_state))
popup.open()
/obj/structure/device/piano/Topic(href, href_list)
/datum/song/Topic(href, href_list)
if(!instrumentObj.Adjacent(usr) || usr.stat)
usr << browse(null, "window=instrument")
usr.unset_machine()
return
instrumentObj.add_fingerprint(usr)
if(href_list["newsong"])
lines = new()
tempo = sanitize_tempo(5) // default 120 BPM
name = ""
else if(href_list["import"])
var/t = ""
do
t = html_encode(input(usr, "Please paste the entire song, formatted:", text("[]", name), t) as message)
if(!in_range(instrumentObj, usr))
return
if(lentext(t) >= INSTRUMENT_MAX_LINE_LENGTH*INSTRUMENT_MAX_LINE_NUMBER)
var/cont = input(usr, "Your message is too long! Would you like to continue editing it?", "", "yes") in list("yes", "no")
if(cont == "no")
break
while(lentext(t) > INSTRUMENT_MAX_LINE_LENGTH*INSTRUMENT_MAX_LINE_NUMBER)
//split into lines
spawn()
lines = splittext(t, "\n")
if(copytext(lines[1],1,6) == "BPM: ")
tempo = sanitize_tempo(600 / text2num(copytext(lines[1],6)))
lines.Cut(1,2)
else
tempo = sanitize_tempo(5) // default 120 BPM
if(lines.len > INSTRUMENT_MAX_LINE_NUMBER)
usr << "Too many lines!"
lines.Cut(INSTRUMENT_MAX_LINE_NUMBER+1)
var/linenum = 1
for(var/l in lines)
if(lentext(l) > INSTRUMENT_MAX_LINE_LENGTH)
usr << "Line [linenum] too long!"
lines.Remove(l)
else
linenum++
updateDialog(usr) // make sure updates when complete
else if(href_list["help"])
help = text2num(href_list["help"]) - 1
else if(href_list["edit"])
edit = text2num(href_list["edit"]) - 1
if(href_list["repeat"]) //Changing this from a toggle to a number of repeats to avoid infinite loops.
if(playing)
return //So that people cant keep adding to repeat. If the do it intentionally, it could result in the server crashing.
repeat += round(text2num(href_list["repeat"]))
if(repeat < 0)
repeat = 0
if(repeat > max_repeats)
repeat = max_repeats
else if(href_list["tempo"])
tempo = sanitize_tempo(tempo + text2num(href_list["tempo"]))
else if(href_list["play"])
playing = 1
spawn()
playsong(usr)
else if(href_list["newline"])
var/newline = html_encode(input("Enter your line: ", instrumentObj.name) as text|null)
if(!newline || !in_range(instrumentObj, usr))
return
if(lines.len > INSTRUMENT_MAX_LINE_NUMBER)
return
if(lentext(newline) > INSTRUMENT_MAX_LINE_LENGTH)
newline = copytext(newline, 1, INSTRUMENT_MAX_LINE_LENGTH)
lines.Add(newline)
else if(href_list["deleteline"])
var/num = round(text2num(href_list["deleteline"]))
if(num > lines.len || num < 1)
return
lines.Cut(num, num+1)
else if(href_list["modifyline"])
var/num = round(text2num(href_list["modifyline"]),1)
var/content = html_encode(input("Enter your line: ", instrumentObj.name, lines[num]) as text|null)
if(!content || !in_range(instrumentObj, usr))
return
if(lentext(content) > INSTRUMENT_MAX_LINE_LENGTH)
content = copytext(content, 1, INSTRUMENT_MAX_LINE_LENGTH)
if(num > lines.len || num < 1)
return
lines[num] = content
else if(href_list["stop"])
playing = 0
updateDialog(usr)
return
if(!in_range(src, usr) || issilicon(usr) || !anchored || !usr.canmove || usr.restrained())
usr << browse(null, "window=piano;size=700x300")
onclose(usr, "piano")
/datum/song/proc/sanitize_tempo(new_tempo)
new_tempo = abs(new_tempo)
return max(round(new_tempo, world.tick_lag), world.tick_lag)
// subclass for handheld instruments, like violin
/datum/song/handheld
/datum/song/handheld/updateDialog(mob/user)
instrumentObj.interact(user)
/datum/song/handheld/shouldStopPlaying()
if(instrumentObj)
return !isliving(instrumentObj.loc)
else
return 1
//////////////////////////////////////////////////////////////////////////
/obj/structure/device/piano
name = "space piano"
desc = "This is a space piano; just like a regular piano, but always in tune! Even if the musician isn't."
icon = 'icons/obj/musician.dmi'
icon_state = "piano"
anchored = 1
density = 1
var/datum/song/song
/obj/structure/device/piano/minimoog
name = "space minimoog"
icon_state = "minimoog"
desc = "This is a minimoog; just like a space piano, but more spacey!"
/obj/structure/device/piano/New()
..()
song = new("piano", src)
if(prob(50))
name = "space minimoog"
desc = "This is a minimoog, like a space piano, but more spacey!"
icon_state = "minimoog"
else
name = "space piano"
desc = "This is a space piano, like a regular piano, but always in tune! Even if the musician isn't."
icon_state = "piano"
/obj/structure/device/piano/Destroy()
qdel(song)
song = null
..()
/obj/structure/device/piano/verb/rotate()
set name = "Rotate Piano"
set category = "Object"
set src in oview(1)
if(istype(usr,/mob/living/simple_mob/animal/passive/mouse))
return
else if(!usr || !isturf(usr.loc))
return
else if(usr.stat || usr.restrained())
return
else if (istype(usr,/mob/observer/ghost) && !config.ghost_interaction)
return
else
src.set_dir(turn(src.dir, 90))
return
if(href_list["newsong"])
song = new()
else if(song)
if(href_list["repeat"]) //Changing this from a toggle to a number of repeats to avoid infinite loops.
if(playing) return //So that people cant keep adding to repeat. If the do it intentionally, it could result in the server crashing.
var/tempnum = input("How many times do you want to repeat this piece? (max:10)") as num|null
if(tempnum > 10)
tempnum = 10
if(tempnum < 0)
tempnum = 0
repeat = round(tempnum)
/obj/structure/device/piano/attack_hand(mob/user)
if(!user.IsAdvancedToolUser())
to_chat(user, "<span class='warning'>You don't have the dexterity to do this!</span>")
return 1
interact(user)
else if(href_list["tempo"])
song.tempo += round(text2num(href_list["tempo"]))
if(song.tempo < 1)
song.tempo = 1
/obj/structure/device/piano/interact(mob/user)
if(!user || !anchored)
return
else if(href_list["play"])
if(song)
playing = 1
spawn() playsong()
else if(href_list["newline"])
var/newline = html_encode(input("Enter your line: ", "Piano") as text|null)
if(!newline)
return
if(song.lines.len > 50)
return
if(lentext(newline) > 50)
newline = copytext(newline, 1, 50)
song.lines.Add(newline)
else if(href_list["deleteline"])
var/num = round(text2num(href_list["deleteline"]))
if(num > song.lines.len || num < 1)
return
song.lines.Cut(num, num+1)
else if(href_list["modifyline"])
var/num = round(text2num(href_list["modifyline"]),1)
var/content = html_encode(input("Enter your line: ", "Piano", song.lines[num]) as text|null)
if(!content)
return
if(lentext(content) > 50)
content = copytext(content, 1, 50)
if(num > song.lines.len || num < 1)
return
song.lines[num] = content
else if(href_list["stop"])
playing = 0
else if(href_list["help"])
help = text2num(href_list["help"]) - 1
else if(href_list["edit"])
edit = text2num(href_list["edit"]) - 1
else if(href_list["import"])
var/t = ""
do
t = html_encode(input(usr, "Please paste the entire song, formatted:", text("[]", src.name), t) as message)
if (!in_range(src, usr))
return
if(lentext(t) >= 3072)
var/cont = input(usr, "Your message is too long! Would you like to continue editing it?", "", "yes") in list("yes", "no")
if(cont == "no")
break
while(lentext(t) > 3072)
//split into lines
spawn()
var/list/lines = splittext(t, "\n")
var/tempo = 5
if(copytext(lines[1],1,6) == "BPM: ")
tempo = 600 / text2num(copytext(lines[1],6))
lines.Cut(1,2)
if(lines.len > 50)
usr << "Too many lines!"
lines.Cut(51)
var/linenum = 1
for(var/l in lines)
if(lentext(l) > 50)
usr << "Line [linenum] too long!"
lines.Remove(l)
else
linenum++
song = new()
song.lines = lines
song.tempo = tempo
updateUsrDialog()
add_fingerprint(usr)
updateUsrDialog()
return
user.set_machine(src)
song.interact(user)
/obj/structure/device/piano/attackby(obj/item/O as obj, mob/user as mob)
if(O.is_wrench())
+1 -1
View File
@@ -19,7 +19,7 @@
update_icon()
return
/obj/structure/noticeboard/initialize()
/obj/structure/noticeboard/Initialize()
for(var/obj/item/I in loc)
if(notices > 4) break
if(istype(I, /obj/item/weapon/paper))
+2 -2
View File
@@ -10,8 +10,8 @@
explosion_resistance = 5
var/list/mobs_can_pass = list(
/mob/living/bot,
/mob/living/simple_animal/slime,
/mob/living/simple_animal/mouse,
/mob/living/simple_mob/slime/xenobio,
/mob/living/simple_mob/animal/passive/mouse,
/mob/living/silicon/robot/drone
)
@@ -59,7 +59,7 @@
var/static/list/possible_states = list("health", "spider", "slime", "emp", "species", "egg", "vent", "mindshock", "viral", "gland")
var/static/list/possible_tech = list(TECH_MATERIAL, TECH_ENGINEERING, TECH_PHORON, TECH_POWER, TECH_BIO, TECH_COMBAT, TECH_MAGNET, TECH_DATA)
/obj/item/prop/alien/junk/initialize()
/obj/item/prop/alien/junk/Initialize()
. = ..()
icon_state = pick(possible_states)
var/list/techs = possible_tech.Copy()
@@ -26,7 +26,7 @@
interaction_message = "<span class='notice'>The prismatic turret seems to be able to rotate.</span>"
/obj/structure/prop/prism/initialize()
/obj/structure/prop/prism/Initialize()
if(degrees_from_north)
animate(src, transform = turn(NORTH, degrees_from_north), time = 3)
@@ -196,7 +196,7 @@
for(var/obj/structure/prop/prism/P in my_turrets)
P.rotate_auto(new_bearing)
/obj/structure/prop/prismcontrol/initialize()
/obj/structure/prop/prismcontrol/Initialize()
..()
if(my_turrets.len) //Preset controls.
for(var/obj/structure/prop/prism/P in my_turrets)
@@ -0,0 +1,67 @@
/obj/structure/prop/nest
name = "diyaab den"
desc = "A den of some creature."
icon = 'icons/obj/structures.dmi'
icon_state = "bonfire"
density = TRUE
anchored = TRUE
interaction_message = "<span class='warning'>You feel like you shouldn't be sticking your nose into a wild animal's den.</span>"
var/disturbance_spawn_chance = 20
var/last_spawn
var/spawn_delay = 150
var/randomize_spawning = FALSE
var/creature_types = list(/mob/living/simple_mob/animal/sif/diyaab)
var/list/den_mobs
var/den_faction //The faction of any spawned creatures.
var/max_creatures = 3 //Maximum number of living creatures this nest can have at one time.
var/tally = 0 //The counter referenced against total_creature_max, or just to see how many mobs it has spawned.
var/total_creature_max //If set, it can spawn this many creatures, total, ever.
/obj/structure/prop/nest/Initialize()
..()
den_mobs = list()
START_PROCESSING(SSobj, src)
last_spawn = world.time
if(randomize_spawning) //Not the biggest shift in spawntime, but it's here.
var/delayshift_clamp = spawn_delay / 10
var/delayshift = rand(delayshift_clamp, -1 * delayshift_clamp)
spawn_delay += delayshift
/obj/structure/prop/nest/Destroy()
den_mobs = null
STOP_PROCESSING(SSobj, src)
..()
/obj/structure/prop/nest/attack_hand(mob/living/user) // Used to tell the player that this isn't useful for anything.
..()
if(user && prob(disturbance_spawn_chance))
spawn_creature(get_turf(src))
/obj/structure/prop/nest/process()
update_creatures()
if(world.time > last_spawn + spawn_delay)
spawn_creature(get_turf(src))
/obj/structure/prop/nest/proc/spawn_creature(var/turf/spawnpoint)
update_creatures() //Paranoia.
if(total_creature_max && tally >= total_creature_max)
return
if(istype(spawnpoint) && den_mobs.len < max_creatures)
last_spawn = world.time
var/spawn_choice = pick(creature_types)
var/mob/living/L = new spawn_choice(spawnpoint)
if(den_faction)
L.faction = den_faction
visible_message("<span class='warning'>\The [L] crawls out of \the [src].</span>")
den_mobs += L
tally++
/obj/structure/prop/nest/proc/remove_creature(var/mob/target)
den_mobs -= target
/obj/structure/prop/nest/proc/update_creatures()
for(var/mob/living/L in den_mobs)
if(L.stat == 2)
remove_creature(L)
@@ -31,7 +31,7 @@
visible_message("<span class='cult'>\The [src] is completely unaffected by the blast.</span>")
return
/obj/machinery/door/blast/puzzle/initialize()
/obj/machinery/door/blast/puzzle/Initialize()
. = ..()
implicit_material = get_material_by_name("dungeonium")
if(locks.len)
+1 -1
View File
@@ -23,7 +23,7 @@
if(climbable)
verbs += /obj/structure/proc/climb_on
/obj/structure/railing/initialize()
/obj/structure/railing/Initialize()
. = ..()
if(src.anchored)
update_icon(0)
+2 -2
View File
@@ -30,7 +30,7 @@ FLOOR SAFES
tumbler_2_open = rand(0, 72)
/obj/structure/safe/initialize()
/obj/structure/safe/Initialize()
. = ..()
for(var/obj/item/I in loc)
if(space >= maxspace)
@@ -175,7 +175,7 @@ obj/structure/safe/ex_act(severity)
plane = TURF_PLANE
layer = ABOVE_UTILITY
/obj/structure/safe/floor/initialize()
/obj/structure/safe/floor/Initialize()
. = ..()
var/turf/T = loc
if(istype(T) && !T.is_plating())
+3 -3
View File
@@ -36,11 +36,11 @@
else
set_opacity(1)
if(material.products_need_process())
processing_objects |= src
START_PROCESSING(SSobj, src)
update_nearby_tiles(need_rebuild=1)
/obj/structure/simple_door/Destroy()
processing_objects -= src
STOP_PROCESSING(SSobj, src)
update_nearby_tiles()
return ..()
@@ -206,6 +206,6 @@
/obj/structure/simple_door/cult/TryToSwitchState(atom/user)
if(isliving(user))
var/mob/living/L = user
if(!iscultist(L) && !istype(L, /mob/living/simple_animal/construct))
if(!iscultist(L) && !istype(L, /mob/living/simple_mob/construct))
return
..()
@@ -76,7 +76,7 @@
src.set_dir(turn(src.dir, 90))
return
else
if(istype(usr,/mob/living/simple_animal/mouse))
if(istype(usr,/mob/living/simple_mob/animal/passive/mouse))
return
if(!usr || !isturf(usr.loc))
return
+30 -18
View File
@@ -21,6 +21,7 @@
var/shardtype = /obj/item/weapon/material/shard
var/glasstype = null // Set this in subtypes. Null is assumed strange or otherwise impossible to dismantle, such as for shuttle glass.
var/silicate = 0 // number of units of silicate
var/fulltile = FALSE // Set to true on full-tile variants.
/obj/structure/window/examine(mob/user)
. = ..(user)
@@ -128,16 +129,10 @@
/obj/structure/window/blob_act()
take_damage(50)
//TODO: Make full windows a separate type of window.
//Once a full window, it will always be a full window, so there's no point
//having the same type for both.
/obj/structure/window/proc/is_full_window()
return (dir == SOUTHWEST || dir == SOUTHEAST || dir == NORTHWEST || dir == NORTHEAST)
/obj/structure/window/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
if(istype(mover) && mover.checkpass(PASSGLASS))
return TRUE
if(is_full_window())
if(is_fulltile())
return FALSE //full tile window, you can't move into it!
if((get_dir(loc, target) & dir) || (get_dir(mover, target) == turn(dir, 180)))
return !density
@@ -204,7 +199,7 @@
user.setClickCooldown(user.get_attack_speed())
if(!damage)
return
if(damage >= 10)
if(damage >= STRUCTURE_MIN_DAMAGE_THRESHOLD)
visible_message("<span class='danger'>[user] smashes into [src]!</span>")
if(reinf)
damage = damage / 2
@@ -386,8 +381,6 @@
anchored = 0
state = 0
update_verbs()
if(is_fulltile())
maxhealth *= 2
health = maxhealth
@@ -414,9 +407,7 @@
//checks if this window is full-tile one
/obj/structure/window/proc/is_fulltile()
if(dir & (dir - 1))
return 1
return 0
return fulltile
//This proc is used to update the icons of nearby windows. It should not be confused with update_nearby_tiles(), which is an atmos proc!
/obj/structure/window/proc/update_nearby_icons()
@@ -456,7 +447,7 @@
// Damage overlays.
var/ratio = health / maxhealth
ratio = Ceiling(ratio * 4) * 25
ratio = CEILING(ratio * 4, 1) * 25
if(ratio > 75)
return
@@ -482,6 +473,10 @@
maxhealth = 12.0
force_threshold = 3
/obj/structure/window/basic/full
maxhealth = 24
fulltile = TRUE
/obj/structure/window/phoronbasic
name = "phoron window"
desc = "A borosilicate alloy window. It seems to be quite strong."
@@ -495,8 +490,8 @@
force_threshold = 5
/obj/structure/window/phoronbasic/full
dir = SOUTHWEST
maxhealth = 80
fulltile = TRUE
/obj/structure/window/phoronreinforced
name = "reinforced borosilicate window"
@@ -512,8 +507,8 @@
force_threshold = 10
/obj/structure/window/phoronreinforced/full
dir = SOUTHWEST
maxhealth = 160
fulltile = TRUE
/obj/structure/window/reinforced
name = "reinforced window"
@@ -528,9 +523,9 @@
force_threshold = 6
/obj/structure/window/reinforced/full
dir = SOUTHWEST
icon_state = "fwindow"
maxhealth = 80
fulltile = TRUE
/obj/structure/window/reinforced/tinted
name = "tinted window"
@@ -565,9 +560,9 @@
var/id
/obj/structure/window/reinforced/polarized/full
dir = SOUTHWEST
icon_state = "fwindow"
maxhealth = 80
fulltile = TRUE
/obj/structure/window/reinforced/polarized/attackby(obj/item/W as obj, mob/user as mob)
if(istype(W, /obj/item/device/multitool) && !anchored) // Only allow programming if unanchored!
@@ -645,3 +640,20 @@
MT.update_icon()
return TRUE
. = ..()
/obj/structure/window/rcd_values(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
switch(passed_mode)
if(RCD_DECONSTRUCT)
return list(
RCD_VALUE_MODE = RCD_DECONSTRUCT,
RCD_VALUE_DELAY = 5 SECONDS,
RCD_VALUE_COST = RCD_SHEETS_PER_MATTER_UNIT * 5
)
/obj/structure/window/rcd_act(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
switch(passed_mode)
if(RCD_DECONSTRUCT)
to_chat(user, span("notice", "You deconstruct \the [src]."))
qdel(src)
return TRUE
return FALSE
@@ -25,7 +25,7 @@
/obj/effect/wingrille_spawn/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0)
return FALSE
/obj/effect/wingrille_spawn/initialize()
/obj/effect/wingrille_spawn/Initialize()
. = ..()
if(!win_path)
return