Stack reorganization, use() now dels after yield

stack/use() now only deletes an empty stack after the current context
yields, removing the need for some awkward patterns when dealing with
stacks. Also adds procs for transferring and splitting stacks.
This commit is contained in:
mwerezak
2014-12-25 01:55:27 -05:00
parent 64e26b2dbd
commit f297f7cd0a
2 changed files with 118 additions and 92 deletions

View File

@@ -7,4 +7,7 @@
return mloc return mloc
/proc/iswall(turf/T) /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

@@ -96,6 +96,43 @@
onclose(user, "stack") onclose(user, "stack")
return 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) /obj/item/stack/Topic(href, href_list)
..() ..()
if ((usr.restrained() || usr.stat || usr.get_active_hand() != src)) if ((usr.restrained() || usr.stat || usr.get_active_hand() != src))
@@ -111,64 +148,37 @@
if (href_list["sublist"]) if (href_list["sublist"])
var/datum/stack_recipe_list/srl = recipes_list[text2num(href_list["sublist"])] var/datum/stack_recipe_list/srl = recipes_list[text2num(href_list["sublist"])]
recipes_list = srl.recipes recipes_list = srl.recipes
var/datum/stack_recipe/R = recipes_list[text2num(href_list["make"])] var/datum/stack_recipe/R = recipes_list[text2num(href_list["make"])]
var/multiplier = text2num(href_list["multiplier"]) var/multiplier = text2num(href_list["multiplier"])
if (!multiplier || (multiplier <= 0)) //href exploit protection if (!multiplier || (multiplier <= 0)) //href exploit protection
return return
if (src.amount < R.req_amount*multiplier)
if (R.req_amount*multiplier>1) src.produce_recipe(R, multiplier, usr)
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
if (src && usr.machine==src) //do not reopen closed window if (src && usr.machine==src) //do not reopen closed window
spawn( 0 ) spawn( 0 )
src.interact(usr) src.interact(usr)
return return
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) if (amount < used)
return 0 return 0
return 1
/obj/item/stack/proc/use(var/used)
if (!can_use(used))
return 0
amount -= used amount -= used
if (amount <= 0) if (amount <= 0)
var/oldsrc = src spawn(0) //delete the empty stack once the current context yields
src = null //dont kill proc after del() if (amount <= 0) //check again in case someone transferred stuff to us
if(usr) if(usr)
usr.before_take_item(oldsrc) usr.before_take_item(src)
del(oldsrc) del(src)
return 1 return 1
/obj/item/stack/proc/add(var/extra) /obj/item/stack/proc/add(var/extra)
@@ -178,71 +188,84 @@
amount += extra amount += extra
return 1 return 1
/obj/item/stack/proc/get_amount() /*
return amount 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.
/obj/item/stack/proc/add_to_stacks(mob/usr as mob) They also remove an equal amount from the source stack.
var/obj/item/stack/oldsrc = src */
src = null
for (var/obj/item/stack/item in usr.loc)
if (item==oldsrc)
continue
if (item.stacktype != oldsrc.stacktype)
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)
break
//attempts to transfer amount to S, and returns the amount actually transferred //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) /obj/item/stack/proc/transfer_to(obj/item/stack/S, var/tamount=null)
if (!amount)
return 0
if (stacktype != S.stacktype) if (stacktype != S.stacktype)
return 0 return 0
if (isnull(tamount)) if (isnull(tamount))
tamount = src.amount tamount = src.amount
var/transfer = min(tamount, src.amount, (S.max_amount - S.amount))
if (transfer) var/transfer = max(min(tamount, src.amount, (S.max_amount - S.amount)), 0)
if (prob(transfer/src.amount *100))
S.copy_evidences(src) //have to do this before use() is called, unfortunately var/orig_amount = src.amount
if (oldsrc.use(transfer)) if (transfer && src.use(transfer))
S.add(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
return transfer var/transfer = max(min(tamount, src.amount, initial(max_amount)), 0)
if (transfer && src.use(transfer))
return new src.type(loc, transfer)
return null
/obj/item/stack/proc/get_amount()
return amount
/obj/item/stack/proc/add_to_stacks(mob/usr as mob)
for (var/obj/item/stack/item in usr.loc)
if (item==src)
continue
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) /obj/item/stack/attack_hand(mob/user as mob)
if (user.get_inactive_hand() == src) if (user.get_inactive_hand() == src)
var/obj/item/stack/F = new src.type(user, 1) var/obj/item/stack/F = src.split(1)
F.copy_evidences(src) if (F)
user.put_in_hands(F) user.put_in_hands(F)
src.add_fingerprint(user) src.add_fingerprint(user)
F.add_fingerprint(user) F.add_fingerprint(user)
use(1) spawn(0)
if (src && usr.machine==src) if (src && usr.machine==src)
spawn(0) src.interact(usr) src.interact(usr)
else else
..() ..()
return return
/obj/item/stack/attackby(obj/item/W as obj, mob/user as mob) /obj/item/stack/attackby(obj/item/W as obj, mob/user as mob)
..() ..()
if (istype(W, /var/obj/item/stack)) if (istype(W, /obj/item/stack))
var/obj/item/stack/S = W var/obj/item/stack/S = W
var/obj/item/stack/oldsrc = src if (user.get_inactive_hand()==src)
src = null src.transfer_to(S, 1)
if (user.get_inactive_hand()==oldsrc)
oldsrc.transfer_to(S, 1)
else else
oldsrc.transfer_to(S) src.transfer_to(S)
if (S && usr.machine==S) spawn(0) //give the stacks a chance to delete themselves if necessary
spawn(0) S.interact(usr) if (S && usr.machine==S)
if (oldsrc && usr.machine==oldsrc) S.interact(usr)
spawn(0) oldsrc.interact(usr) if (src && usr.machine==src)
src.interact(usr)
else return ..() else return ..()
/obj/item/stack/proc/copy_evidences(obj/item/stack/from as obj) /obj/item/stack/proc/copy_evidences(obj/item/stack/from as obj)
@@ -258,8 +281,8 @@
/datum/stack_recipe /datum/stack_recipe
var/title = "ERROR" var/title = "ERROR"
var/result_type var/result_type
var/req_amount = 1 var/req_amount = 1 //amount of material needed for this recipe
var/res_amount = 1 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/max_res_amount = 1
var/time = 0 var/time = 0
var/one_per_turf = 0 var/one_per_turf = 0