ID:166614
 
i have a baisc smithing system. But what i need it to do is to check if the usr has a certain amount of bars to make a certain item. I have no clue how to due this, I dont know DM very well so if you could show it too me in code i would understand how to do it better. I'm not a person to copy and paste. Even editing my current code would be great. Here below is my code:
    Anvil
icon='tiles.dmi'
icon_state ="anvil"
density=1
verb
Smith()
set src in oview(1)
var/check=input("What type of bar do you wish to smith?") in list ("Bronze",)
if(check=="Bronze")
var/obj/bronze= locate(/obj/bronzebar) in usr.contents
if(bronze)
var/smith=input("What would you like to smith") in list ("Dagger","Sword","Bigsword","Battleaxe","Claws")
if(smith=="Dagger")
var/obj/bars = locate(/obj/bronzebar) in usr.contents
if(bars)
usr<<"You begin to hammer out a bronze dagger!"
sleep(20)
del(bars)
usr.contents+=new/obj/weapons/Bronze_Dagger
usr<<"You made a bronze dagger!"
else
usr<<"You do not have enough bars!"
You could make a function that returns a list of all the objects of a specified type, then you have them all in one conveniently stored list and you can also see how many of them there are by accessing list.len
atom/proc/mass_locate(object_type)
var/list/L[0] //This is the list of objects, currently empty
for(var/atom/A in contents)
if(A.type == object_type) //If it's the type we're after, add it to L
L += A
return L

Then you can just use that function and set its return value to a list.

The following example use of the function checks to see if you have 5 tomatos to trade for a rug, and the second use below will take all your tomatoes and pay you for them.
mob/rug_merchant/verb/buy_rug()
set src in view()
var/list/tomatoes_to_trade = usr.mass_locate(/obj/tomato)
if(tomatoes_to_trade.len < 5) //You have less than 5 tomatoes
usr << "I require 5 tomatoes to trade for a rug."
return
for(var/index = 1 to 5)
var/obj/tomato/tomato = locate() in tomatoes_to_trade
tomato.Move(src)
var/obj/rug/rug = new(usr)
usr << "Thank you. Please come again."

mob/art_collector/verb/sell_rugs()
set src in view()
var/list/rugs_to_sell = usr.mass_locate(/obj/rug)
if(!rugs_to_sell.len) //You don't have any rugs
usr << "Please come back when you have some rugs."
return
var/sell_count = input("How many rugs will you sell to me?", "Sell Rugs (1 to [rugs_to_sell.len])") as null|num
if(!sell_count) return
//Now I'm about to check to make sure you still have the rugs.
//Depending on what can happen in the game, you might have lost one while inputting a number.
rugs_to_sell = usr.mass_locate(/obj/rug)
if(rugs_to_sell.len < sell_count)
usr << "You do not have [sell_count] rugs!"
return
for(var/index = 1 to sell_count)
var/obj/rug/rug = locate() in rugs_to_sell
rug.Move(src)
usr << "Thank you for the rugs. Here is [5*sell_count] dollars for them."
usr.money += 5*sell_count

You could also alter the original function to only return up to a maximum number of objects, then you could skip some of the checking and looping extras I did. You could also put in a minimum, so that it returns none of them if you don't have a certain amount.
atom/proc/mass_locate(object_type, min = 0, max = 0)
var/list/L[0] //This is the list of objects, currently empty
for(var/atom/A in contents)
if(A.type == object_type) //If it's the type we're after, add it to L
L += A
if(L.len < min) L = new
if(L.len > max) L = L.Copy(1, max+1)
return L

Then you could do something like the following.
mob/buyer/verb/sell_5_tomatoes()
var/list/tomatoes = usr.mass_locate(/obj/tomato, 5, 5)
if(!tomatoes.len) return
for(var/obj/O in tomatoes) O.Move(src)
usr.money += tomatoes.len
usr << "Thank you. Here is [tomatoes.len] dollars."
In response to Loduwijk
Thank you so much.

But I don't get these parts
 
var/list/L[0]//do i need to have the []? and do i put the bars as /obj/bronzebars?

atom/proc/mass_locate(object_type)//do i put the bars for the object_type? or is it a pre-defined thing?

the code i did do already is:
atom
proc
locate_bars(/obj/bronzebar,min=1,max=5)
var/list/B =(/obj/bronzebar)

which gave me 3 errors
objects.dm:105:error:bronzebar :duplicate definition
Turfs.dm:213:error:bronzebar :duplicate definition
Turfs.dm:214:error:B :invalid proc definition
bump
In response to FriesOfDoom
FriesOfDoom wrote:
But I don't get these parts
 
> var/list/L[0]//do i need to have the []? and do i put the bars as /obj/bronzebars?
>
> atom/proc/mass_locate(object_type)//do i put the bars for the object_type? or is it a pre-defined thing?
>


Yes, the "[0]" part tells it "I want this variable set to a new list with 0 elements." And as for the bars, the "object_type" is just a variable name. That should work fine as it is. That is a variable that keeps track of the object type passed to it.

the code i did do already is:
> atom
> proc
> locate_bars(/obj/bronzebar,min=1,max=5)
> var/list/B =(/obj/bronzebar)
>

which gave me 3 errors
objects.dm:105:error:bronzebar :duplicate definition
Turfs.dm:213:error:bronzebar :duplicate definition
Turfs.dm:214:error:B :invalid proc definition

I'm not sure exactly what you are doing there. Are you trying to define the function again under another name? Are you trying to call it? What?

Either way, indentation is off somehow. If you're redefining it again under a different function name there, you changed the variable to a type path (object_type to /obj/bronzebar) and the list is not indented far enough, and you set the list to /obj/bronzebar which I don't understand.

Perhaps I should just repeat the initial question and let you explain instead of asking a game of 20 questions. What exactly are you trying to do with that second code snippet you showed there?
In response to Loduwijk
lol >.<i was testing if i understood the code, which obviously i didn't. I changed it because i wanted to check if the user had bars, then depending on the item if they had enough bars, then let them make the item, which the highest item will only take 5 bars and the lowest will only take 1. Because im a nooblet to coding :P i interpeted the (object_type)as you defenition of "put the object being searched for here" sorry. The reason I did the var/list/B(B for bars :P)= /obj/bronzebars is the same as above, i didnt understand 100%.
This the first game I've made that i've actually had to program so im new to programming entiraly(<<<looks like I cant spell either -.-). <br/>
so with the whole [0] thing if i wanted to have like 5 types of bars would i put [5]?

Thanks for your patients in helping me understand this.
In response to FriesOfDoom
As for the function, I typed that exactly as it should be. That is finished and doesn't need changing. You just drop it into the code, and then you can use the function anywhere, just like you use other functions. So nothing needs changing in the mass_locate function.

As for that "[0]" part, that is supposed to stay as 0. It starts out with a list with 0 things in it, then the function adds things as appropriate.

As for using it, I gave several examples. As for your specific use, if you want to see if you have 5 bars for something, then you would just do...
    Anvil
icon='tiles.dmi'
icon_state ="anvil"
density=1
verb
Smith()
set src in oview(1)
var/check=input("What type of bar do you wish to smith?") in list ("Bronze",)
if(check=="Bronze")
var/bronze_bars = usr.mass_locate(/obj/bronzebar)
if(bronze_bars.len)
var/smith=input("What would you like to smith") in list ("Dagger","Sword","Bigsword","Battleaxe","Claws")
bronze_bars = usr.mass_locate(/obj/bronzebar) //Let's check that again since it might have changed while we were selecting some input.
if(smith=="Dagger")
if(bronze_bars.len >= 1)
usr<<"You begin to hammer out a bronze dagger!"
sleep(20)
del(bronze_bars[1])
usr.contents+=new/obj/weapons/Bronze_Dagger
usr<<"You made a bronze dagger!"
else
usr<<"You do not have enough bars!"

Also, I have several suggestions that you might like which can make your work a lot easier.

First, I suggest you look up switch in the reference, as it can make your code more organised and easier to keep track of when you have many things to check for. It's used like the following.
mob/verb/test_money()
//This assumes your money is >= 0 and that you can't have more than 100
switch(money)
if(0)
src << "You have no money."
if(50)
src << "Whoa! That's a lot of money. Your wallet is half full."
if(90 to 99)
src << "Your wallet is almost full, let's go shopping."
if(100)
src << "Quick, dump some out, your wallet is about to explode!"
else
src << "You have [money] dollars."

You can use that when checking between lists of things like your material types and the type of item the player wants to make.

Also, to make it easier to add other types of material and types of objects later, you could use text2path to cut way back on the code needed. In fact, if you use this variation, you don't need to use switch at all since you don't need to check for material and object stuff. Watch this...
...
var/material = input("What type of material do you want to use?") in list("Bronze", "Copper", "Steel", "Silver", "Gold")
var/bar_type = text2path("/obj/[lowertext(material)]bar")
//In the case of bronze, the above line makes bar_type equal /obj/bronzebar. If it were silver, it would return /obj/silverbar, and so on.
var/list/bars = usr.mass_locate(bar_type)
if(!bars.len)
usr << "You don't have any [material] bars."
return
var/item = input("What would you like to smith") in list ("Dagger","Sword","Bigsword","Battleaxe","Claws")
var/item_type = text2path("/obj/weapons/[material]_[item]")
bars = usr.mass_locate(bar_type) //checking it again to be sure
if(!bars.len)
usr << "You don't have any [material] bars."
return
usr << "You begin to hammer out a [material] [item]!"
sleep(20)
del(bars[1])
new item_type(usr)
usr << "You made a [material] [item]!"

Of course, that sleeps the same amount of time no matter what you are making and it only uses 1 bar for anything. There are several ways you could fix that. The way I'm going to suggest has you create the crafted item up front, then if you succeed in making it, it moves into your contents, but if you fail, it just gets deleted.
...
var/material = input("What type of material do you want to use?") in list("Bronze", "Copper", "Steel", "Silver", "Gold")
var/bar_type = text2path("/obj/[lowertext(material)]bar")
//In the case of bronze, the above line makes bar_type equal /obj/bronzebar. If it were silver, it would return /obj/silverbar, and so on.
var/list/bars = usr.mass_locate(bar_type)
if(!bars.len)
usr << "You don't have any [material] bars."
return
var/item = input("What would you like to smith") in list ("Dagger","Sword","Bigsword","Battleaxe","Claws")
var/item_type = text2path("/obj/weapons/[material]_[item]")
var/obj/weapons/O = new item_type
bars = usr.mass_locate(bar_type) //checking it again to be sure
if(bars.len < O.material_required)
usr << "You need [O.material_required] bars to make the [O.name]."
return
usr << "You begin to hammer out the [O.name]!"
sleep(20 * O.material_required)
for(var/index = 1 to O.material_required)
del(bars[index])
O.loc = usr
usr << "You made the [O.name]!"

Notice how I assumed you have a variable for the object which keeps track of how many bars it takes to craft itself. If you do not have such a variable and you want to use this model, you can just define such a variable for craftable items.

I also thought about making use of the min and max parameters for the max_locate function here and doing "mass_locate(bar_type, O.material_required, O.material_required)" If I had done that, I could have just looped through all bars in the list and deleted them when the time came, like so...
...
for(var/bar in bars)
del(bar)
...

But I decided not to, as I recalled you saying something about allowing for more bars to be used in some situations if you had them, or something like that. So, with this way, you can add in some checks if you want to modify bar consumption. For example, if your character is proficient with crafting weapons of an altered size...
...
var/item_type = text2path("/obj/weapons/[material]_[item]")
var/obj/weapons/O = new item_type
if(usr.class == "Crafter of Giant Tools")
var/n = input("How many extra bars do you want to commit?") as num
if(n > 0)
O.material_required += n
O.attack_power *= 1 + n/10
O.attack_power = round(O.attack_power)
O.name = "Large [O.name]"
bars = usr.mass_locate(bar_type) //checking it again to be sure
if(bars.len < O.material_required)
usr << "You need [O.material_required] bars to make the [O.name]."
return
usr << "You begin to hammer out the [O.name]!"
sleep(20 * O.material_required)
for(var/index = 1 to O.material_required)
del(bars[index])
O.loc = usr
usr << "You made the [O.name]!"

That would allow the "Crafter of Giant Tools" to make enlarged weapons which inflict more damage. The attack_power goes up by one-tenth for every extra bar used in its creation, so 10 extra bars means x2 damage, 20 means x3, and so on.

I hope you liked that last example, and I hope all this helped.
In response to Loduwijk
Wow, Lodu. Thats amazing. :O
In response to Loduwijk
:O :):::::


Your.......awsome man.....thank you so much, you've made a coding noob happy. I never imagined some of the ways you showed me how to do it, and its so much more organized and cleaner. I'll that I need to do now is add the player getting experience(done). Next time I have a question, i'm asking you! Is there anyway I could aprentice under you?
THANK YOU SO MUCH!!!!!!!:D
In response to FriesOfDoom
FriesOfDoom wrote:
:O :):::::


I never imagined some of the ways you showed me how to do it, and its so much more organized and cleaner.

It's nothing overly special (I'd like to think so, but I'm not unique.) It just comes with years and thousands of hours of practice.

Next time I have a question, i'm asking you!

Don't forget that there are plenty of other accomplished programmers on Byond. Keep up to date on the developer section of the Byond forums and you'll see who to look for, and you can try to go out of your way to read their replies and learn from their style.

Is there anyway I could aprentice under you?

I've tried to teach people in the past with varying degrees of success, though the ones that are willing to put in the time and effort and not skip past things usually do well enough. Unfortunately though, I do not have nearly as much free time as I used to in years past, as I have a job now and am also currently in college.

I am taking a course about learning to better tutor people in the fall semester, so after that I should be even better able to help peopel, and I am also working on a tutorial which I hope will be easier to use and help people who have no programming experience. You'll have to have a look through that if I ever finish it (I am notorious for leaving projects unfinished =/ ).
In response to Loduwijk
XD i drop alot of things 2 lol, I look for it when it come out, and thanks again