Files
Bubberstation/code/game/objects/structures/toiletbong.dm
T
Bloop c2f6a4408d Fixes toilet bongs, and fixes a serious bug in the crafting system (#72893)
## About The Pull Request

The PR everyone has been waiting for...fixed toilet bong crafting. Now
you can craft them just as before using the new crafting system.


![image](https://user-images.githubusercontent.com/13398309/213944308-74b3e50e-965d-4e69-9025-d011764b3247.png)

In attempting to fix this I encountered one of the gnarliest, nastiest,
meanest and most infuriatingly difficult to debug bugs I have come
across so far. And it's existed for as long as the crafting system has,
but due to unique circumstances it has been allowed to go unnoticed this
whole time.

Technical details below. Full list of changes here:

- crafting recipes can now contain structures as part of their
requirements
- removed deprecated var 'additional_req_tex' and changed text to use
the 'steps' list instead so they actually show in the gui
- toilet bongs are now passable terrain like normal toilets are
- fixed an atrocious bug with crafting that was by pure coincidence not
causing any problems
- this bug would prevent any recipes that did not contain a material
from deleting properly
- this bug would also cause any recipes that are supposed to use but not
consume machinery to consume them regardless

---

Basically, the bug that took me hours upon hours of debugging and
head-scratching to find is this:

from crafting.dm:
```
	main_loop:
		for(var/path_key in requirements)
			amt = R.reqs[path_key] || R.machinery[path_key]
			if(!amt)//since machinery can have 0 aka CRAFTING_MACHINERY_USE - i.e. use it, don't consume it!
				continue main_loop
```
specifically this line:

`amt = R.reqs[path_key] || R.machinery[path_key] `

The culprit ended up being that if you do machinery[path_key] on an
empty list, it can lead to very unexpected behavior (see: EXITING THE
FUNCTION without actually doing anything).

I spent so much time thinking that item deletion wasn't working because
amt was being set to 0, false, or null perhaps when no, it wasn't that.
The function was just exiting out even before the (!amt) check due to
the atrocities committed by someone before me.

Setting amt = `R.reqs[path_key] || R.machinery[path_key]` on the other
hand always evaluates to a positive integer (either the successfully
retrieved reqs amt, or a 1 from the OR expression). It was only by
coincidence that the code did what it was supposed to, because:

1) Every single recipe has R_reqs, so the first part will never cause
the function-exiting failure because the list is never empty.
2) As for the second part of the expression, there are no recipes that
make use of CRAFTING_MACHINERY_USE, so the fact that machinery[path_key]
was never actually being accessed and thus set to a var (which is what
causes the function to exit) didn't matter.

So these two things together have basically allowed a really bad bug to
go unnoticed this whole time. I only noticed it because when trying to
add a third part to the expression it just did not work at all how you
would expect.

The solution is rather simply to add a check like so:
```

	main_loop:
		for(var/path_key in requirements)
			amt = R.reqs?[path_key] || R.machinery?[path_key]
			if(!amt)//since machinery can have 0 aka CRAFTING_MACHINERY_USE - i.e. use it, don't consume it!
				continue main_loop
```

Fixes https://github.com/Skyrat-SS13/Skyrat-tg/issues/18732 .

## Why It's Good For The Game

Fixes a bug with crafting that would inevitably torment someone else as
soon as they tried to add the right kind of recipe, if that hasn't
already happened by now.

<details>
<summary>Toilet bongs are back baby!!</summary>


![image](https://user-images.githubusercontent.com/13398309/213941079-ae7d007a-ca92-4de3-9de6-7a156b4a0618.png)

</details>

## Changelog
🆑
fix: toilet bongs crafting recipes
fix: fixed crafting itself
refactor: cleaned up some old code in the recipes file, added support
for structures in recipes
/🆑
2023-01-23 12:53:28 +01:00

110 lines
3.7 KiB
Plaintext

/obj/structure/toiletbong
name = "toilet bong"
desc = "A repurposed toilet with re-arranged piping and an attached flamethrower. Why would anyone build this?"
icon = 'icons/obj/watercloset.dmi'
icon_state = "toiletbong"
density = FALSE
anchored = TRUE
var/emagged = FALSE
var/smokeradius = 1
var/mutable_appearance/weed_overlay
/obj/structure/toiletbong/Initialize(mapload)
. = ..()
create_storage()
atom_storage.attack_hand_interact = FALSE
atom_storage.set_holdable(list(/obj/item/food/))
atom_storage.max_total_storage = 100
atom_storage.max_slots = 12
weed_overlay = mutable_appearance('icons/obj/watercloset.dmi', "toiletbong_overlay")
START_PROCESSING(SSobj, src)
/obj/structure/toiletbong/update_icon()
. = ..()
cut_overlays()
if (LAZYLEN(contents))
add_overlay(weed_overlay)
/obj/structure/toiletbong/attack_hand(mob/living/carbon/user)
. = ..()
if (!anchored)
user.balloon_alert(user, "secure it first!")
return
if (!LAZYLEN(contents))
user.balloon_alert(user, "it's empty!")
return
user.visible_message(span_boldnotice("[user] takes a huge drag on the [src]."))
if (do_after(user, 2 SECONDS, target = src))
var/turf/toiletbong_location = loc
toiletbong_location.hotspot_expose(1000, 5)
for (var/obj/item/item in contents)
if (item.resistance_flags & INDESTRUCTIBLE)
user.balloon_alert(user, "[item.name] is blocking the pipes!")
continue
playsound(src, 'sound/items/modsuit/flamethrower.ogg', 50)
var/datum/effect_system/fluid_spread/smoke/chem/smoke_machine/puff = new
puff.set_up(smokeradius, holder = src, location = user, carry = item.reagents, efficiency = 20)
puff.start()
if (prob(5) && !emagged)
if(islizard(user))
user.balloon_alert(user, "a hidden treat!")
user.visible_message(span_danger("[user] fishes a mouse out of the pipes."))
else
to_chat(user, span_userdanger("There was something disgusting in the pipes!"))
user.visible_message(span_danger("[user] spits out a mouse."))
user.adjust_disgust(50)
user.vomit(10)
var/mob/living/spawned_mob = new /mob/living/basic/mouse(get_turf(user))
spawned_mob.faction |= "[REF(user)]"
if(prob(50))
for(var/j in 1 to rand(1, 3))
step(spawned_mob, pick(NORTH,SOUTH,EAST,WEST))
qdel(item)
if(!emagged)
break
update_icon()
/obj/structure/toiletbong/wrench_act(mob/living/user, obj/item/tool)
tool.play_tool_sound(src)
if(anchored)
to_chat(user, span_notice("You begin unsecuring the [src]."))
anchored = FALSE
else
to_chat(user, span_notice("You secure the [src] to the floor."))
anchored = TRUE
return TRUE
/obj/structure/toiletbong/crowbar_act(mob/living/user, obj/item/tool)
if(anchored)
return FALSE
tool.play_tool_sound(src)
to_chat(user, span_notice("You begin taking apart the [src]."))
if (!do_after(user, 10 SECONDS, target = src))
return FALSE
new /obj/item/flamethrower(get_turf(src))
new /obj/item/stack/sheet/iron(get_turf(src))
var/obj/item/tank/internals/plasma/ptank = new /obj/item/tank/internals/plasma(get_turf(src))
ptank.air_contents.gases[/datum/gas/plasma][MOLES] = (0)
qdel(src)
return TRUE
/obj/structure/toiletbong/AltClick(mob/living/user)
if(anchored)
return ..()
setDir(turn(dir,90))
playsound(src, 'sound/items/deconstruct.ogg', 50)
return
/obj/structure/toiletbong/emag_act(mob/user, obj/item/card/emag/emag_card)
playsound(src, 'sound/effects/fish_splash.ogg', 50)
user.balloon_alert(user, "whoops!")
if(!emagged)
emagged = TRUE
smokeradius = 2
to_chat(user, span_boldwarning("The [emag_card.name] falls into the toilet. You fish it back out. Looks like you broke the toilet."))
/obj/structure/toiletbong/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/card/emag))
return
. = ..()