Last active
December 29, 2016 11:37
-
-
Save BlueNexus/8ec11259c4f8ac612dec61894f43de74 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Stack type objects! | |
* Contains: | |
* Stacks | |
* Recipe datum | |
* Recipe list datum | |
*/ | |
/* | |
* Stacks | |
*/ | |
/obj/item/stack | |
gender = PLURAL | |
origin_tech = list(TECH_MATERIAL = 1) | |
var/list/datum/stack_recipe/recipes | |
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 | |
var/build_type = null //used when directly applied to a turf | |
var/uses_charge = 0 | |
var/list/charge_costs = null | |
var/list/datum/matter_synth/synths = null | |
/obj/item/stack/New(var/loc, var/amount=null) | |
..() | |
if (!stacktype) | |
stacktype = type | |
if (amount) | |
src.amount = amount | |
return | |
/obj/item/stack/Destroy() | |
if(uses_charge) | |
return 1 | |
if (src && usr && usr.machine == src) | |
usr << browse(null, "window=stack") | |
return ..() | |
/obj/item/stack/examine(mob/user) | |
if(..(user, 1)) | |
if(!uses_charge) | |
to_chat(user, "There [src.amount == 1 ? "is" : "are"] [src.amount] [src.singular_name]\s in the stack.") | |
else | |
to_chat(user, "There is enough charge for [get_amount()].") | |
/obj/item/stack/attack_self(mob/user as mob) | |
list_recipes(user) | |
/obj/item/stack/proc/list_recipes(mob/user as mob, recipes_sublist) | |
if (!recipes) | |
return | |
if (!src || get_amount() <= 0) | |
user << browse(null, "window=stack") | |
user.set_machine(src) //for correct work of onclose | |
var/list/recipe_list = recipes | |
if (recipes_sublist && recipe_list[recipes_sublist] && istype(recipe_list[recipes_sublist], /datum/stack_recipe_list)) | |
var/datum/stack_recipe_list/srl = recipe_list[recipes_sublist] | |
recipe_list = srl.recipes | |
var/t1 = text("<HTML><HEAD><title>Constructions from []</title></HEAD><body><TT>Amount Left: []<br>", src, src.get_amount()) | |
for(var/i=1;i<=recipe_list.len,i++) | |
var/E = recipe_list[i] | |
if (isnull(E)) | |
t1 += "<hr>" | |
continue | |
if (i>1 && !isnull(recipe_list[i-1])) | |
t1+="<br>" | |
if (istype(E, /datum/stack_recipe_list)) | |
var/datum/stack_recipe_list/srl = E | |
t1 += "<a href='?src=\ref[src];sublist=[i]'>[srl.title]</a>" | |
if (istype(E, /datum/stack_recipe)) | |
var/datum/stack_recipe/R = E | |
var/max_multiplier = round(src.get_amount() / R.req_amount) | |
var/title as text | |
var/can_build = 1 | |
can_build = can_build && (max_multiplier>0) | |
if (R.res_amount>1) | |
title+= "[R.res_amount]x [R.title]\s" | |
else | |
title+= "[R.title]" | |
title+= " ([R.req_amount] [src.singular_name]\s)" | |
if (can_build) | |
t1 += text("<A href='?src=\ref[src];sublist=[recipes_sublist];make=[i];multiplier=1'>[title]</A> ") | |
else | |
t1 += text("[]", title) | |
continue | |
if (R.max_res_amount>1 && max_multiplier>1) | |
max_multiplier = min(max_multiplier, round(R.max_res_amount/R.res_amount)) | |
t1 += " |" | |
var/list/multipliers = list(5,10,25) | |
for (var/n in multipliers) | |
if (max_multiplier>=n) | |
t1 += " <A href='?src=\ref[src];make=[i];multiplier=[n]'>[n*R.res_amount]x</A>" | |
if (!(max_multiplier in multipliers)) | |
t1 += " <A href='?src=\ref[src];make=[i];multiplier=[max_multiplier]'>[max_multiplier*R.res_amount]x</A>" | |
t1 += "</TT></body></HTML>" | |
user << browse(t1, "window=stack") | |
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) | |
to_chat(user, "<span class='warning'>You haven't got enough [src] to build \the [produced] [recipe.title]\s!</span>") | |
else | |
to_chat(user, "<span class='warning'>You haven't got enough [src] to build \the [recipe.title]!</span>") | |
return | |
if (recipe.one_per_turf && (locate(recipe.result_type) in user.loc)) | |
to_chat(user, "<span class='warning'>There is another [recipe.title] here!</span>") | |
return | |
if (recipe.on_floor && !isfloor(user.loc)) | |
to_chat(user, "<span class='warning'>\The [recipe.title] must be constructed on the floor!</span>") | |
return | |
if (recipe.time) | |
to_chat(user, "<span class='notice'>Building [recipe.title] ...</span>") | |
if (!do_after(user, recipe.time)) | |
return | |
if (use(required)) | |
var/atom/O | |
if(recipe.use_material) | |
O = new recipe.result_type(user.loc, recipe.use_material) | |
else | |
O = new recipe.result_type(user.loc) | |
O.set_dir(user.dir) | |
O.add_fingerprint(user) | |
if(recipe.goes_in_hands) | |
user.put_in_hands(O) | |
if (istype(O, /obj/item/stack)) | |
var/obj/item/stack/S = O | |
S.amount = produced | |
S.add_to_stacks(user) | |
if (istype(O, /obj/item/weapon/storage)) //BubbleWrap - so newly formed boxes are empty | |
for (var/obj/item/I in O) | |
qdel(I) | |
/obj/item/stack/Topic(href, href_list) | |
..() | |
if ((usr.restrained() || usr.stat || usr.get_active_hand() != src)) | |
return | |
if (href_list["sublist"] && !href_list["make"]) | |
list_recipes(usr, text2num(href_list["sublist"])) | |
if (href_list["make"]) | |
if (src.get_amount() < 1) qdel(src) //Never should happen | |
var/list/recipes_list = recipes | |
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 | |
src.produce_recipe(R, multiplier, usr) | |
if (src && usr.machine==src) //do not reopen closed window | |
spawn( 0 ) | |
src.interact(usr) | |
return | |
return | |
//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 (get_amount() < used) | |
return 0 | |
return 1 | |
/obj/item/stack/proc/use(var/used) | |
if (!can_use(used)) | |
return 0 | |
if(!uses_charge) | |
amount -= used | |
if (amount <= 0) | |
if(usr) | |
usr.remove_from_mob(src) | |
qdel(src) //should be safe to qdel immediately since if someone is still using this stack it will persist for a little while longer | |
return 1 | |
else | |
if(get_amount() < used) | |
return 0 | |
for(var/i = 1 to charge_costs.len) | |
var/datum/matter_synth/S = synths[i] | |
S.use_charge(charge_costs[i] * used) // Doesn't need to be deleted | |
return 1 | |
return 0 | |
/obj/item/stack/proc/add(var/extra) | |
if(!uses_charge) | |
if(amount + extra > get_max_amount()) | |
return 0 | |
else | |
amount += extra | |
return 1 | |
else if(!synths || synths.len < uses_charge) | |
return 0 | |
else | |
for(var/i = 1 to uses_charge) | |
var/datum/matter_synth/S = synths[i] | |
S.add_charge(charge_costs[i] * extra) | |
/* | |
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, var/type_verified) | |
if (!get_amount()) | |
return 0 | |
if ((stacktype != S.stacktype) && !type_verified) | |
return 0 | |
if (isnull(tamount)) | |
tamount = src.get_amount() | |
var/transfer = max(min(tamount, src.get_amount(), (S.get_max_amount() - S.get_amount())), 0) | |
var/orig_amount = src.get_amount() | |
if (transfer && src.use(transfer)) | |
S.add(transfer) | |
if (prob(transfer/orig_amount * 100)) | |
transfer_fingerprints_to(S) | |
if(blood_DNA) | |
S.blood_DNA |= blood_DNA | |
return transfer | |
return 0 | |
//creates a new stack with the specified amount | |
/obj/item/stack/proc/split(var/tamount) | |
if (!amount) | |
return null | |
if(uses_charge) | |
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) | |
newstack.color = color | |
if (prob(transfer/orig_amount * 100)) | |
transfer_fingerprints_to(newstack) | |
if(blood_DNA) | |
newstack.blood_DNA |= blood_DNA | |
return newstack | |
return null | |
/obj/item/stack/proc/get_amount() | |
if(uses_charge) | |
if(!synths || synths.len < uses_charge) | |
return 0 | |
var/datum/matter_synth/S = synths[1] | |
. = round(S.get_charge() / charge_costs[1]) | |
if(charge_costs.len > 1) | |
for(var/i = 2 to charge_costs.len) | |
S = synths[i] | |
. = min(., round(S.get_charge() / charge_costs[i])) | |
return | |
return amount | |
/obj/item/stack/proc/get_max_amount() | |
if(uses_charge) | |
if(!synths || synths.len < uses_charge) | |
return 0 | |
var/datum/matter_synth/S = synths[1] | |
. = round(S.max_energy / charge_costs[1]) | |
if(uses_charge > 1) | |
for(var/i = 2 to uses_charge) | |
S = synths[i] | |
. = min(., round(S.max_energy / charge_costs[i])) | |
return | |
return max_amount | |
/obj/item/stack/proc/add_to_stacks(mob/user as mob) | |
for (var/obj/item/stack/item in user.loc) | |
if (item==src) | |
continue | |
var/transfer = src.transfer_to(item) | |
if (transfer) | |
to_chat(user, "<span class='notice'>You add a new [item.singular_name] to the stack. It now contains [item.amount] [item.singular_name]\s.</span>") | |
if(!amount) | |
break | |
/obj/item/stack/get_storage_cost() //Scales storage cost to stack size | |
. = ..() | |
if (amount < max_amount) | |
. = ceil(. * amount / max_amount) | |
/obj/item/stack/attack_hand(mob/user as mob) | |
if (user.get_inactive_hand() == src) | |
var/N = input("How many stacks of [src] would you like to split off?", "Split stacks", 1) as num|null | |
if(N) | |
var/obj/item/stack/F = src.split(N) | |
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, /obj/item/stack)) | |
var/obj/item/stack/S = W | |
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 ..() | |
/* | |
* Recipe datum | |
*/ | |
/datum/stack_recipe | |
var/title = "ERROR" | |
var/result_type | |
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 | |
var/on_floor = 0 | |
var/use_material | |
var/goes_in_hands = 0 | |
New(title, result_type, req_amount = 1, res_amount = 1, max_res_amount = 1, time = 0, one_per_turf = 0, on_floor = 0, supplied_material = null, goes_in_hands = 0) | |
src.title = title | |
src.result_type = result_type | |
src.req_amount = req_amount | |
src.res_amount = res_amount | |
src.max_res_amount = max_res_amount | |
src.time = time | |
src.one_per_turf = one_per_turf | |
src.on_floor = on_floor | |
src.use_material = supplied_material | |
src.goes_in_hands = goes_in_hands | |
/* | |
* Recipe list datum | |
*/ | |
/datum/stack_recipe_list | |
var/title = "ERROR" | |
var/list/recipes = null | |
New(title, recipes) | |
src.title = title | |
src.recipes = recipes |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment