Merge pull request #7534 from mwerezak/doors

Doors and stacks
This commit is contained in:
Zuhayr
2014-12-28 13:14:23 +10:30
7 changed files with 194 additions and 95 deletions

View File

@@ -7,4 +7,7 @@
return mloc
/proc/iswall(turf/T)
return (istype(T, /turf/simulated/wall) || istype(T, /turf/unsimulated/wall) || istype(T, /turf/simulated/shuttle/wall))
return (istype(T, /turf/simulated/wall) || istype(T, /turf/unsimulated/wall) || istype(T, /turf/simulated/shuttle/wall))
/proc/isfloor(turf/T)
return (istype(T, /turf/simulated/floor) || istype(T, /turf/unsimulated/floor) || istype(T, /turf/simulated/shuttle/floor))

View File

@@ -855,7 +855,7 @@ About the new airlock wires panel:
return
src.add_fingerprint(user)
if((istype(C, /obj/item/weapon/weldingtool) && !( src.operating > 0 ) && src.density))
if(!repairing && (istype(C, /obj/item/weapon/weldingtool) && !( src.operating > 0 ) && src.density))
var/obj/item/weapon/weldingtool/W = C
if(W.remove_fuel(0,user))
if(!src.welded)
@@ -869,7 +869,7 @@ About the new airlock wires panel:
else if(istype(C, /obj/item/weapon/screwdriver))
if (src.p_open)
if (stat & BROKEN)
usr << "The airlock control panel is too damaged to be closed!"
usr << "<span class='warning'>The panel is broken and cannot be closed.</span>"
else
src.p_open = 0
else
@@ -884,7 +884,7 @@ About the new airlock wires panel:
else if(istype(C, /obj/item/weapon/pai_cable)) // -- TLE
var/obj/item/weapon/pai_cable/cable = C
cable.plugin(src, user)
else if(istype(C, /obj/item/weapon/crowbar))
else if(!repairing && istype(C, /obj/item/weapon/crowbar))
var/beingcrowbarred = null
if(istype(C, /obj/item/weapon/crowbar) )
beingcrowbarred = 1 //derp, Agouri
@@ -1121,7 +1121,7 @@ About the new airlock wires panel:
update_icon()
/obj/machinery/door/airlock/proc/hasPower()
return ((src.secondsMainPowerLost==0 || src.secondsBackupPowerLost==0) && !(stat & NOPOWER))
return ((src.secondsMainPowerLost==0 || src.secondsBackupPowerLost==0) && !(stat & NOPOWER|BROKEN))
/obj/machinery/door/airlock/proc/prison_open()
src.unlock()

View File

@@ -2,6 +2,8 @@
#define DOOR_OPEN_LAYER 2.7 //Under all objects if opened. 2.7 due to tables being at 2.6
#define DOOR_CLOSED_LAYER 3.1 //Above most items if closed
#define DOOR_REPAIR_AMOUNT 50 //amount of health regained per stack amount used
/obj/machinery/door
name = "Door"
desc = "It opens and closes."
@@ -29,6 +31,7 @@
var/emitter_resistance = 10 // Amount of emitter hits doors whistand
var/min_force = 10 //minimum amount of force needed to damage the door with a melee weapon
var/hitsound = 'sound/weapons/smash.ogg' //sound door makes when hit with a weapon
var/obj/item/stack/sheet/metal/repairing
//Multi-tile doors
dir = EAST
@@ -162,7 +165,6 @@
tforce = AM:throwforce
playsound(src.loc, hitsound, 100, 1)
take_damage(tforce)
//..() //Does this really need to be here twice? The parent proc doesn't even do anything yet. - Nodrak
return
/obj/machinery/door/attack_ai(mob/user as mob)
@@ -185,27 +187,69 @@
user = null
if(!src.requiresID())
user = null
if(istype(I, /obj/item/stack/sheet/metal))
if(stat & BROKEN)
user << "\blue [src.name] is damaged beyond repair and must be reconstructed!"
user << "<span class='notice'>It looks like \the [src] is pretty busted. It's going to need more than just patching up now.</span>"
return
if(health >= maxhealth)
user << "\blue Nothing to fix!"
user << "<span class='notice'>Nothing to fix!</span>"
return
if(!density)
user << "<span class='warning'>\The [src] must be closed before you can repair it.</span>"
return
//figure out how much metal we need
var/amount_needed = (maxhealth - health) / DOOR_REPAIR_AMOUNT
amount_needed = (round(amount_needed) == amount_needed)? amount_needed : round(amount_needed) + 1 //Why does BYOND not have a ceiling proc?
var/obj/item/stack/sheet/metal/metalstack = I
var/health_per_sheet = 50
var/initialhealth = health
src.health = min(maxhealth, health + 100, health + (metalstack.amount * health_per_sheet))
user.visible_message("\The [user] patches some dents on \the [src] with \the [metalstack].")
metalstack.use(round((health - initialhealth)/health_per_sheet))
var/transfer
if (repairing)
transfer = metalstack.transfer_to(repairing, amount_needed - repairing.amount)
if (!transfer)
user << "<span class='warning'>You must weld or remove \the [repairing] from \the [src] before you can add anything else.</span>"
else
repairing = metalstack.split(amount_needed)
if (repairing)
repairing.loc = src
transfer = repairing.amount
if (transfer)
user << "<span class='notice'>You fit [transfer] [metalstack.singular_name]\s to damaged and broken parts on \the [src].</span>"
return
if(src.density && ((operable() && istype(I, /obj/item/weapon/card/emag)) || istype(I, /obj/item/weapon/melee/energy/blade)))
if(repairing && istype(I, /obj/item/weapon/weldingtool))
if(!density)
user << "<span class='warning'>\The [src] must be closed before you can repair it.</span>"
return
var/obj/item/weapon/weldingtool/welder = I
if(welder.remove_fuel(0,user))
user << "<span class='notice'>You start to fix dents and weld \the [repairing] into place.</span>"
playsound(src, 'sound/items/Welder.ogg', 100, 1)
if(do_after(user, 5 * repairing.amount) && welder && welder.isOn())
user << "<span class='notice'>You finish repairing the damage to \the [src].</span>"
health = between(health, health + repairing.amount*DOOR_REPAIR_AMOUNT, maxhealth)
update_icon()
del(repairing)
return
if(repairing && istype(I, /obj/item/weapon/crowbar))
user << "<span class='notice'>You remove \the [repairing].</span>"
playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1)
repairing.loc = user.loc
repairing = null
return
if(src.density && (operable() && istype(I, /obj/item/weapon/card/emag)))
flick("door_spark", src)
sleep(6)
open()
operating = -1
return 1
//psa to whoever coded this, there are plenty of objects that need to call attack() on doors without bludgeoning them.
if(src.density && istype(I, /obj/item/weapon) && user.a_intent == "hurt" && !istype(I, /obj/item/weapon/card))
var/obj/item/weapon/W = I
@@ -213,16 +257,18 @@
if(W.force < min_force)
user.visible_message("\red <B>\The [user] hits \the [src] with \the [W] with no visible effect.</B>" )
else
user.visible_message("\red <B>\The [user] forcefully slams \the [src] with \the [W]!</B>" )
user.visible_message("\red <B>\The [user] forcefully strikes \the [src] with \the [W]!</B>" )
playsound(src.loc, hitsound, 100, 1)
take_damage(W.force)
return
if(src.allowed(user) && operable())
if(src.density)
open()
else
close()
return
if(src.density && !(stat & (NOPOWER|BROKEN)))
flick("door_deny", src)
return

View File

@@ -28,6 +28,7 @@
icon_state = "sheet-glass"
matter = null
created_window = /obj/structure/window/basic
stacktype = /obj/item/stack/sheet/glass
/obj/item/stack/sheet/glass/attack_self(mob/user as mob)
construct_window(user)

View File

@@ -140,6 +140,7 @@ obj/item/stack/sheet/mineral/iron/New()
name = "plastic sheets"
icon_state = "sheet-plastic"
perunit = 2000
stacktype = /obj/item/stack/sheet/mineral/plastic
/obj/item/stack/sheet/mineral/gold
name = "gold"

View File

@@ -92,6 +92,7 @@ var/global/list/datum/stack_recipe/metal_recipes = list ( \
icon_state = "sheet-metal"
throwforce = 14.0
flags = FPRINT | TABLEPASS | CONDUCT
stacktype = /obj/item/stack/sheet/metal
/obj/item/stack/sheet/metal/New(var/loc, var/amount=null)
recipes = metal_recipes
@@ -152,6 +153,7 @@ var/global/list/datum/stack_recipe/wood_recipes = list ( \
desc = "One can only guess that this is a bunch of wood."
singular_name = "wood plank"
icon_state = "sheet-wood"
stacktype = /obj/item/stack/sheet/wood
/obj/item/stack/sheet/wood/New(var/loc, var/amount=null)
recipes = wood_recipes

View File

@@ -16,9 +16,12 @@
var/singular_name
var/amount = 1
var/max_amount //also see stack recipes initialisation, param "max_res_amount" must be equal to this max_amount
var/stacktype //determines whether different stack types can merge
/obj/item/stack/New(var/loc, var/amount=null)
..()
if (!stacktype)
stacktype = type
if (amount)
src.amount = amount
return
@@ -93,6 +96,43 @@
onclose(user, "stack")
return
/obj/item/stack/proc/produce_recipe(datum/stack_recipe/recipe, var/quantity, mob/user)
var/required = quantity*recipe.req_amount
var/produced = min(quantity*recipe.res_amount, recipe.max_res_amount)
if (!can_use(required))
if (produced>1)
user << "\red You haven't got enough [src] to build \the [produced] [recipe.title]\s!"
else
user << "\red You haven't got enough [src] to build \the [recipe.title]!"
return
if (recipe.one_per_turf && (locate(recipe.result_type) in user.loc))
user << "\red There is another [recipe.title] here!"
return
if (recipe.on_floor && !isfloor(user.loc))
user << "\red \The [recipe.title] must be constructed on the floor!"
return
if (recipe.time)
user << "\blue Building [recipe.title] ..."
if (!do_after(user, recipe.time))
return
if (use(required))
var/atom/O = new recipe.result_type(user.loc)
O.set_dir(user.dir)
O.add_fingerprint(user)
if (istype(O, /obj/item/stack))
var/obj/item/stack/S = O
S.amount = produced
if (istype(O, /obj/item/weapon/storage)) //BubbleWrap - so newly formed boxes are empty
for (var/obj/item/I in O)
del(I)
/obj/item/stack/Topic(href, href_list)
..()
if ((usr.restrained() || usr.stat || usr.get_active_hand() != src))
@@ -108,64 +148,37 @@
if (href_list["sublist"])
var/datum/stack_recipe_list/srl = recipes_list[text2num(href_list["sublist"])]
recipes_list = srl.recipes
var/datum/stack_recipe/R = recipes_list[text2num(href_list["make"])]
var/multiplier = text2num(href_list["multiplier"])
if (!multiplier || (multiplier <= 0)) //href exploit protection
return
if (src.amount < R.req_amount*multiplier)
if (R.req_amount*multiplier>1)
usr << "\red You haven't got enough [src] to build \the [R.req_amount*multiplier] [R.title]\s!"
else
usr << "\red You haven't got enough [src] to build \the [R.title]!"
return
if (R.one_per_turf && (locate(R.result_type) in usr.loc))
usr << "\red There is another [R.title] here!"
return
if (R.on_floor && !istype(usr.loc, /turf/simulated/floor))
usr << "\red \The [R.title] must be constructed on the floor!"
return
if (R.time)
usr << "\blue Building [R.title] ..."
if (!do_after(usr, R.time))
return
if (src.amount < R.req_amount*multiplier)
return
var/atom/O = new R.result_type( usr.loc )
O.set_dir(usr.dir)
if (R.max_res_amount>1)
var/obj/item/stack/new_item = O
new_item.amount = R.res_amount*multiplier
//new_item.add_to_stacks(usr)
src.amount-=R.req_amount*multiplier
if (src.amount<=0)
var/oldsrc = src
src = null //dont kill proc after del()
usr.before_take_item(oldsrc)
del(oldsrc)
if (istype(O,/obj/item) && istype(usr,/mob/living/carbon))
usr.put_in_hands(O)
O.add_fingerprint(usr)
//BubbleWrap - so newly formed boxes are empty
if ( istype(O, /obj/item/weapon/storage) )
for (var/obj/item/I in O)
del(I)
//BubbleWrap END
src.produce_recipe(R, multiplier, usr)
if (src && usr.machine==src) //do not reopen closed window
spawn( 0 )
src.interact(usr)
return
return
/obj/item/stack/proc/use(var/used)
//Return 1 if an immediate subsequent call to use() would succeed.
//Ensures that code dealing with stacks uses the same logic
/obj/item/stack/proc/can_use(var/used)
if (amount < used)
return 0
return 1
/obj/item/stack/proc/use(var/used)
if (!can_use(used))
return 0
amount -= used
if (amount <= 0)
var/oldsrc = src
src = null //dont kill proc after del()
if(usr)
usr.before_take_item(oldsrc)
del(oldsrc)
spawn(0) //delete the empty stack once the current context yields
if (amount <= 0) //check again in case someone transferred stuff to us
if(usr)
usr.before_take_item(src)
del(src)
return 1
/obj/item/stack/proc/add(var/extra)
@@ -175,62 +188,95 @@
amount += extra
return 1
/*
The transfer and split procs work differently than use() and add().
Whereas those procs take no action if the desired amount cannot be added or removed these procs will try to transfer whatever they can.
They also remove an equal amount from the source stack.
*/
//attempts to transfer amount to S, and returns the amount actually transferred
/obj/item/stack/proc/transfer_to(obj/item/stack/S, var/tamount=null)
if (!amount)
return 0
if (stacktype != S.stacktype)
return 0
if (isnull(tamount))
tamount = src.amount
var/transfer = max(min(tamount, src.amount, (S.max_amount - S.amount)), 0)
var/orig_amount = src.amount
if (transfer && src.use(transfer))
S.add(transfer)
if (prob(transfer/orig_amount * 100))
S.copy_evidences(src)
return transfer
return 0
//creates a new stack with the specified amount
/obj/item/stack/proc/split(var/tamount)
if (!amount)
return null
var/transfer = max(min(tamount, src.amount, initial(max_amount)), 0)
var/orig_amount = src.amount
if (transfer && src.use(transfer))
var/obj/item/stack/newstack = new src.type(loc, transfer)
if (prob(transfer/orig_amount * 100))
newstack.copy_evidences(src)
return newstack
return null
/obj/item/stack/proc/get_amount()
return amount
/obj/item/stack/proc/add_to_stacks(mob/usr as mob)
var/obj/item/stack/oldsrc = src
src = null
for (var/obj/item/stack/item in usr.loc)
if (item==oldsrc)
if (item==src)
continue
if (!istype(item, oldsrc.type))
continue
if (item.amount>=item.max_amount)
continue
oldsrc.attackby(item, usr)
usr << "You add new [item.singular_name] to the stack. It now contains [item.amount] [item.singular_name]\s."
if(!oldsrc)
var/transfer = src.transfer_to(item)
if (transfer)
usr << "You add a new [item.singular_name] to the stack. It now contains [item.amount] [item.singular_name]\s."
if(!amount)
break
/obj/item/stack/attack_hand(mob/user as mob)
if (user.get_inactive_hand() == src)
var/obj/item/stack/F = new src.type(user, 1)
F.copy_evidences(src)
user.put_in_hands(F)
src.add_fingerprint(user)
F.add_fingerprint(user)
use(1)
if (src && usr.machine==src)
spawn(0) src.interact(usr)
var/obj/item/stack/F = src.split(1)
if (F)
user.put_in_hands(F)
src.add_fingerprint(user)
F.add_fingerprint(user)
spawn(0)
if (src && usr.machine==src)
src.interact(usr)
else
..()
return
/obj/item/stack/attackby(obj/item/W as obj, mob/user as mob)
..()
if (istype(W, src.type))
if (istype(W, /obj/item/stack))
var/obj/item/stack/S = W
if (S.amount >= max_amount)
return 1
var/to_transfer as num
if (user.get_inactive_hand()==src)
to_transfer = 1
src.transfer_to(S, 1)
else
to_transfer = min(src.amount, S.max_amount-S.amount)
S.add(to_transfer)
if (S && usr.machine==S)
spawn(0) S.interact(usr)
src.use(to_transfer)
if (src && usr.machine==src)
spawn(0) src.interact(usr)
src.transfer_to(S)
spawn(0) //give the stacks a chance to delete themselves if necessary
if (S && usr.machine==S)
S.interact(usr)
if (src && usr.machine==src)
src.interact(usr)
else return ..()
/obj/item/stack/proc/copy_evidences(obj/item/stack/from as obj)
src.blood_DNA = from.blood_DNA
src.fingerprints = from.fingerprints
src.fingerprintshidden = from.fingerprintshidden
src.fingerprintslast = from.fingerprintslast
src.blood_DNA |= from.blood_DNA
src.fingerprints |= from.fingerprints
src.fingerprintshidden |= from.fingerprintshidden
src.fingerprintslast = from.fingerprintslast
//TODO bloody overlay
/*
@@ -239,8 +285,8 @@
/datum/stack_recipe
var/title = "ERROR"
var/result_type
var/req_amount = 1
var/res_amount = 1
var/req_amount = 1 //amount of material needed for this recipe
var/res_amount = 1 //amount of stuff that is produced in one batch (e.g. 4 for floor tiles)
var/max_res_amount = 1
var/time = 0
var/one_per_turf = 0