# How do Prescription Lenses work This isn't going to be much of a tutorial but it's a start. This is an overview of how to code a relatively simple item I added recently, which maybe you could use as a springboard to try it yourself. I am going to explain what the changes in this file are doing: https://github.com/lizardqueenlexi/orbstation/pull/276/files What we want to do here is make an item which you can apply to any glasses to make them into prescription glasses. ## Making our item We're going to start by defining our new item ``` /obj/item/prescription_lenses ``` The way you define new types of things in byond code is by writing a type path (pictured above). This works as a kind of map to define what behaviours it has. This type is an `obj`, meaning essentially... not a creature or environment tile and an `item`, a type of `obj` which you can pick up in your hands This means that any behaviour defined on either `obj` or `item` is automatically included in our new type. Typepaths can get a lot longer than this (like `/obj/item/clothing/head/helmet/knight/greyscale`) if they're inheriting a lot of behaviour, but this is a pretty simple item. Technically this is actually an `/atom/obj/item/prescription_lenses` because all `obj` are also children of the type `atom`, but because almost everything is an atom we don't tend to bother to write that part out. `atom` contains every object which has some kind of physical presence in the game world and contains all of the code for "having an appearance" and "being in a location". Strictly speaking we could just define this as `/item/prescription_lenses` and it would be able to assume the `obj` part too, but convention is to write it all out in order to be clearer. ## Indentation After that we want to fill in a bunch of simple properties which are already defined on `obj` or `item` ``` /obj/item/prescription_lenses name = "prescription lenses" icon = 'orbstation/icons/obj/accessibility.dmi' icon_state = "lenses" desc = "Use on any pair of glasses to attach corrective prescription lenses. \ The added weight means they might fall off if you get into a scrape." w_class = WEIGHT_CLASS_TINY ``` Something that is quite important! You may notice that all of these properties are indented one tab to the right, this is how BYOND knows that they are related to the typepath above it. If they were on the same level, BYOND would start thinking you are trying to define some new thing called `name` instead of editing the `name` of `/obj/item/prescription_lenses`. Getting your indentation right is important. Other place this is used are for things like loops or if statements. ``` if (x > y) do z do a ``` This code would "do z" if `x` is bigger than `y` but will *always* "do a" because `do a` is not indented to be "inside" the if statement. ## Setting up properties ``` /obj/item/prescription_lenses name = "prescription lenses" icon = 'orbstation/icons/obj/accessibility.dmi' icon_state = "lenses" desc = "Use on any pair of glasses to attach corrective prescription lenses. \ The added weight means they might fall off if you get into a scrape." w_class = WEIGHT_CLASS_TINY ``` The rest (as in the actual `property = thing`) is all hopefully pretty easy to understand. The `name` is obviously what it is called, the `desc` is what pops up when it is examined. `icon` is a reference to an icon file somewhere in our file structure which contains a sprite sheet, and `icon_state` is the name of the sprite on that sprite sheet to use. The above are all properties of `atom`. `w_class` is a property of `item` describing how big the item is for the purposes of what kinds of inventory can contain it. We want this to be tiny because lenses are tiny and you should be able to put them in your pockets or cardboard boxes. As I said earlier, our `obj/item/prescription_lenses` has every property of `atom`, `obj`, and `item`. Anything we *don't* provide with a value here will fall back to how it is defined in its parent object. If we removed the line `w_class = WEIGHT_CLASS_TINY` then it would instead default to `WEIGHT_CLASS_MEDIUM` because that is how it is defined in `item`. Additionally, there are things we are intentionally leaving as default such as `pass_flags = PASSTABLE` from `item` (meaning that when you throw this is passes over tables rather than hitting them) and `force = 0` from `obj` (meaning that when you hit someone with it, it does 0 damage). The default values are already what we want, so we don't need to bother writing them out again. If you want to see what those properties are, right clicking on `obj` or `item` in the type path in the Visual Studio Code development environment should allow you to "go to definition", where you can see everything else that it does. Most of these properties *should* have descriptive names and comments, but some older ones likely don't and you might have to experiment to see what they are for. ## Making it do something At this point if we launched the game then we'd be able to spawn this item (with admin tools, we haven't added a way for players to get it yet...) and see it, move it around with our inventory, and examine it. Next we want it to actually do something. ``` /obj/item/prescription_lenses/afterattack( obj/item/clothing/glasses/target_glasses, mob/user, proximity) ``` This part is where we start to get a little more technical. `item` has a `proc` called `afterattack`. A `proc` (standing for procedure) is essentially "an action this can perform" and is what you use to store code for performing any kind of action. `afterattack` as the name implies is called after you attack something with the item (or, click on something with the item). Into `afterattack` are passed three properties; 1. `obj/item/clothing/glasses/target_glasses` 2. `mob/user` 3. `proximity` You can see from the long type path that #1 is intended to be "some glasses". The final part of the type path is the name of the variable being passed in, so if we want to refer to it in code we call it `target_glasses`. #2 is pretty easy to understand the same way, it's a `mob` (a creature of some sort) which performed the attack. #3 doesn't have any type path at all, it's just a value! This could be essentially anything, but in this case from looking at the base definition of `item/proc/afterattack` we can see that it should be either `TRUE` or `FALSE` and represents whether you're stood next to the thing you are attacking. So whenever someone clicks on something else while holding this item, this proc will run and it will know those three things about what just happened. Now we need to actually make that do something. Here's everything that this proc does: ``` . = ..() if (!proximity) return if (!istype(target_glasses)) return if (!isturf(target_glasses.loc)) user.balloon_alert(user, "take glasses off") //They need to be outside your inventory or the trait won't apply return if (target_glasses.vision_correction) user.balloon_alert(user, "already corrective") return user.visible_message(span_notice("[user] starts attaching [src] to [target_glasses].")) if (!do_after(user, 5 SECONDS, target = target_glasses)) user.balloon_alert(user, "interrupted") return target_glasses.vision_correction = TRUE user.balloon_alert(user, "success") target_glasses.AddComponent(/datum/component/knockoff, 25, list(BODY_ZONE_PRECISE_EYES), slot_flags) qdel(src) ``` Now I will go through each line and explain what is going on ## . = ..() `. = ..()` This is a notorious BYONDism which looks like nonsense if you have never seen it before. I will try to break down what it means. `.` represents the "returned value" of a proc. Whenever you call a proc it will "return" some kind of value, even if often that value is "nothing". If you had a proc like this: ``` /thing/add_two_numbers(a, b) // This isn't how you define a new proc but for simplicity return a + b ``` `.` here would be the sum of whatever `a` and `b` are. `..()` means "call the version of this proc defined in the parent". So in this case it means "run all of the code in the definition of `afterattack` which you can read in `obj/item`" So we could have: ``` /thing/secondthing/add_two_numbers(a, b) . = ..() . += 2 ``` If you ran this proc then you would first do the `a + b` behaviour we defined above, then you would add two to that value. The important part of this operation *here* and why we are doing this is just that we need to make sure that what `/obj/item` wants to do in `afterattack` keeps happening, because it's important to how the game works. ## Validation Now with that out of the way, what else are we doing? The next series of operations are all very similar. ``` if (!proximity) return if (!istype(target_glasses)) return if (!isturf(target_glasses.loc)) user.balloon_alert(user, "take glasses off") //They need to be outside your inventory or the trait won't apply return if (target_glasses.vision_correction) user.balloon_alert(user, "already corrective") return ``` Here is where we perform a bunch of checks to make sure we actually want to do our "upgrade some glasses" behaviour. `if (!proximity) return` This is simply checking "are we next to the thing we just hit?" and if it's not, we `return` You might think "of course I am next to the thing or I couldn't have hit it" but this is where you are introduced to the bane of coders everywhere: Telekinesis. Also you might have been teleported by some action intervening between you clicking on the glasses and use making this check, who knows! `return` ends the command, so any time we `return` we are giving up on upgrading some glasses. As noted earlier you can `return` with some value, but there's no need to here. `if (!istype(target_glasses)) return` You might notice that up above we defined `obj/item/clothing/glasses/target_glasses` but then I kept saying that this proc is run *any time* that you hit *anything* with our prescription lenses. We only care about glasses here, but `target_glasses` could actually be any object at all! So on this line `istype(target_glasses)` performs a check to find out if `target_glasses` is actually `obj/item/clothing/glasses`. If it isn't, we `return`, because it's not glasses. `if (!isturf(target_glasses.loc))` Here we want to check if the glasses are currently inside someone's inventory. We don't want people to switch the lenses of glasses which are currently being held or worn (not for any balance reason, it's just that updating the glasses to be prescription ones wouldn't work until you took them off and put them back on anyway). `target_glasses.loc` contains information about "where are the glasses currently". `isturf(target_glasses.loc)` checks if the location the glasses currently are is a `turf`. `turf` represents all of the floor and wall game tiles, if the location of the glasses *isn't* part of a `turf` then it's in someone's inventory. Something which is on a table is still *also* on a turf, it's only being "inside" something which prevents that from being true. `user.balloon_alert(user, "take glasses off") ` It'd be confusing if we just returned here, so we're calling a handy proc called `balloon_alert` on the `user` telling them to take their glasses off first. This is what displays those little sentences which float out of your character. They have the benefit of both being more visible than the chat log, but also more temporary. These are great for action feedback because that stuff doesn't need to be in the long-term log but should probably be pretty visible. It's generally a good idea to give users feedback about why their interaction isn't working if they would otherwise be confused. `if (target_glasses.vision_correction)` Finally, the operation we are going to perform is to enable `vision_correction` on `target_glasses`. If `vision_correction` is *already* enabled, then we don't need to do that! Once again we tell the user why we ended here, but I explained how that works already. Finally we have confirmed that: * Someone is hitting something with some lenses. * They are stood next to the thing they are hitting. * The thing they are hitting is glasses. * The glasses they are hitting are not inside an inventory. * The glasses they are hitting are not prescription glasses. That means we're ready to turn that thing into prescription glasses! ## Actually doing the thing ``` user.visible_message(span_notice("[user] starts attaching [src] to [target_glasses].")) if (!do_after(user, 5 SECONDS, target = target_glasses)) user.balloon_alert(user, "interrupted") return target_glasses.vision_correction = TRUE user.balloon_alert(user, "success") target_glasses.AddComponent(/datum/component/knockoff, 25, list(BODY_ZONE_PRECISE_EYES), slot_flags) qdel(src) ``` `user.visible_message` prints a message to everyone who can see `user` (including the user). This proc allows you to write a different message that the user sees if you want, but I didn't bother. `span_notice` describes how the text is formatted, there are a lot of different `span_` helpers like `span_warning` or `span_robo` or `span_reallybig` depending on what kind of text you want. Inside the text we put `[user]` to automatically fill in the name of the user, and the same for `[src]` to fill in the name of our item and `[target_glasses]` to fill in the name of the item we are upgrading. You can format basically any property this way, so we could print `[src.icon_state]` if we wanted to for some reason, although this wouldn't be useful information. If you don't specify a property it defaults to its name, which is what we want. `src` is a special variable which simply represents "the thing this proc belongs to". `if (!do_after(user, 5 SECONDS, target = target_glasses))` `do_after` is a proc which starts a progress bar and then returns `TRUE` if the bar goes to completion or `FALSE` if you are interrupted for any reason. We pass in `user` as the mob performing the action, `5 SECONDS` as the time we want it to take, and `target = target_glasses` as the target of our action (so if someone grabs your glasses off the table in front of you, it will fail). This is wrapped in an `if` check, so if the action returns `FALSE` we show another balloon alert and then `return`, you didn't manage to finish upgrading your glasses for some reason! `target_glasses.vision_correction = TRUE` This is what this has all been leading up to. The glasses object has a variable `vision_correction`, and when you put on some glasses it checks this flag to see if it is `TRUE` or `FALSE` and updates your vision accordingly. Now that we have set it to `TRUE`, whenever someone wears these glasses they will be able to see clearly! `user.balloon_alert(user, "success")` You hopefully know what this is doing at this point. `target_glasses.AddComponent(/datum/component/knockoff, 25, list(BODY_ZONE_PRECISE_EYES), slot_flags)` This is me being a little mean. All prescription glasses have a "component" called `/datum/component/knockoff`. This is what makes it so that if you fall over, sometimes your glasses fall off. Because I think that this is funny, I want this behaviour to be inherited by any other glasses you upgrade too. Components are convenient ways to package behaviours which could theoretically exist on any game object, but explaining exactly how they work is a little out of scope for what I am trying to write here. Suffice to say, what we are doing here is attaching the `/datum/component/knockoff` component to our glasses, configuring it to trigger `25`% of the time, telling it to only trigger if your eyes are affected, and telling it to only trigger if the glasses are currently equipped on your eyes (so they won't slip out of your pockets or backpack). `qdel(src)` Finally, we delete our glasses lenses. They're "inside" the glasses now, so the item shouldn't stick around! `qdel` does some complicated stuff with garbage collection and you can read up on it by searching for `HARDDELETES.MD` in the codebase but suffice to say, this is simply the operation you call to delete something, and we are passing it `src` because we want to delete ourselves. ## Acquiring it in the game Now we have our cool item but nobody can actually get it, so we add a crafting recipe. ``` /datum/crafting_recipe/prescription_lenses name = "Prescription Lens Kit" result = /obj/item/prescription_lenses time = 1.5 SECONDS reqs = list(/obj/item/clothing/glasses/regular = 1) tool_behaviors = list(TOOL_SCREWDRIVER) category = CAT_CLOTHING ``` I am hopeful that given what I explained above, you *might* be able to decipher what this is doing by yourself. The one detail I think isn't explained is what a `datum` is in this type path. Previously we defined an `atom` which is an object which exists in the game world. A `datum` conversely is some code which simply represents a kind of intangible concept... so in this case, a crafting recipe! The rest of what is happening here is simply extending the properties of `/datum/crafting_recipe` as we did when we created `/obj/item/prescription_lenses` and relying on the baseline behaviour of `/datum/crafting_recipe` to add our new recipe to the list automatically. Let me know if you need any further clarification!