ID:2018348
 
(See the best response by Lummox JR.)
runtime error: type mismatch: Perk (/obj/perk) += Perk 2 (/obj/perk)
proc name: BuyPerk (/mob/verb/BuyPerk)
source file: test3.dm,82
usr: (src)
src: Tavren (/mob)
src.loc: null
call stack:
Tavren (/mob): BuyPerk()
Line 82:acquired_perks += buy
acquired_perks is a list var containing individual players bought perks
buy is the var of the verb BuyPerk
Such as:
mob/verb/BuyPerk()
set category = "Commands"
var/obj/perk/buy = input("Which Perk?") as null | anything in perk

The rest I'd rather not show

READ THIS IF YOU NEED MORE INFO:
Basically, Admins make the perk it saves to a list where players buy the perk with points, if they manage to get all the requirements of the perk they buy it. Then it saves to a var list acquired_perks. There is an option for admins to make a perk they already made a "Required Perk" Meaning a player needs to have the perk to buy the next perk. In the Buy perk verb. There is an if statement saying basically if the player has the perk that requires the perk they are trying to buy they can buy it.

You didn't actually include the line where the error occurred. We can't help you without context.

Also, I removed the <b> tag from your post, because it was making the post unreadable.
The line was 82 which was acquired_perks += buy. Am I understanding you wrong? Do you need the whole programming? Or just the one line?
I don't think you're actually create a new instance of the obj being bought. It looks like you're just setting the obj that's in the perk list as a /obj/perk/buy reference, and then trying to add it to the player's acquired_perks list.
What do you suggest I do?
In response to Flameguru
Flameguru wrote:
The line was 82 which was acquired_perks += buy. Am I understanding you wrong? Do you need the whole programming? Or just the one line?

I need the whole proc, because the tiny bit of the proc you shared doesn't show the line that had the error, and there's no context to figure out where the type mismatch is appearing.
Best response
The goto abuse here is really horrendous. There are places where goto isn't even doing anything, and others where you could simply skip over a bunch of stuff if it was written with correct if/else branches. So first things first: let's clear up the goto abuse.

The goto statement should be avoided at all costs by novice programmers. It's the kind of thing that only makes sense to use once you have more advanced flow patterns.

This is the same code with only the goto problem fixed, and all cases of usr changed to src (since they're the same in this verb, it makes more sense to use src; from now on I'm calling that Ter's Law).

mob/verb/BuyPerk()
set category = "Commands"
var/obj/perk/buy = input("Which Perk?") as null | anything in perk
if(buy == null)
src << "Nothing in the Shop to buy!"
return
if(points < buy.cost)
src << "You dont have enough points for [buy]. The cost is [buy.cost]."
return
if(!HasNR2())
if(skillgrade[SkillGrade] < skillgrade[buy.required_skillgrade])
src << "You dont have the required skill grade: [buy.required_skillgrade]."
return
if(buy.required_perk != "No Requirement")
if(buy.required_perk != acquired_perks)
src << "You dont have the required perk: [buy.required_perk]."
return
if(!HasNR3() && !clan[Clan] == clan[buy.required_clan])
src << "You dont have the required clan: [buy.required_clan]."
return
if(points >= buy.cost || skillgrade[SkillGrade] == skillgrade[buy.required_skillgrade] || clan[Clan] == clan[buy.required_clan] || HasPerk(buy.required_perk))
buy.loc = src
points -= buy.cost
src << "You bought the perk [buy] for [buy.cost]"
acquired_perks += buy

This corrected code is a million times clearer. And now I see what the problem is: You're not paying any attention to what the acquired_perks var is or what it's supposed to be.

Presumably, acquired_perks is meant to be a list of perks. I would imagine it's defined like so:

mob/var/list/acquired_perks

You're making two big mistakes in this verb. The first is here:

if(buy.required_perk != acquired_perks)

If acquired_perks is a list, or null if it hasn't been setup yet, then buy.required_perk will never equal acquired_perks, because the former is either an object or a type path, and the latter is a list. What I think you meant was:

if(!(locate(buy.required_perk.type) in acquired_perks))

Here I'm assuming required_perk is an object rather than a type path, but I'd have to see how this system is defined to fix it properly. This is something you'll have to revisit, because a lot depends on how you've written the whole perk system.

The other big mistake in the verb is this one:

acquired_perks += buy

The reason that's a mistake is that apparently, acquired_perks has never been initialized as a list. Your runtime error tells me that when you buy the first perk, you've added null += a perk and the var is set to a single perk, not a list of them; when you buy the second, you're trying to add two objects together and hence the error.

It's actually a good thing that acquired_perks is null to start with, but you need to make sure it becomes a list before you add anything to it. Therefore:

if(!acquired_perks) acquired_perks = list()
acquired_perks += buy
I see. So I have a few more questions then I believe thats it. I changed this line:
   if(points >= buy.cost || skillgrade[SkillGrade] == skillgrade[buy.required_skillgrade] || clan[Clan] == clan[buy.required_clan] || HasPerk(buy.required_perk))

To this(I replaced HasPerk at the end):
    if(points >= buy.cost || skillgrade[SkillGrade] == skillgrade[buy.required_skillgrade] || clan[Clan] == clan[buy.required_clan] || !acquired_perks[acquired_perks] == list())


Does this work out?

As for the type in
if(!(locate(buy.required_perk.type) in acquired_perks))
The perk system is set up in obj/perk so its an object
Meaning no disrespect, I get the strong impression that you're just trying things at random to see what works, rather than taking the time to work out what each var is and what it does. (Going along with that, I'm going to hazard a guess that you didn't write all this source yourself, but instead you're modifying someone else's source.)

Here's why I think that:

!acquired_perks[acquired_perks] == list()

That bit of code doesn't make any sense. The only way to get code like that is to stick a bunch of vars and operators together pretty much at random without working out what they'll do. And the if() statement that you've changed here doesn't actually have anything to do with the code changes I mentioned; you've changed code that didn't need to be changed.
Well you are wrong. This code is not even in a game yet its just in testing on a blank DM. So yes I have written most of it except the part that not is from you guys helping me
Okay, that's good--because working from someone else's source is often a bad idea, and it gets a lot of programmers into trouble when they make changes. Most of the source that's floating around is really terrible, so it's not very robust when it comes to changes.

It's important to take a deep breath and work through the problem. For example let's take apart that line of code I mentioned earlier:

!acquired_perks[acquired_perks] == list()

That says:

1) Look up a value from the acquired_perks list, using itself as an index. (If acquired_perks is not already a list, this will result in an error.)

2) Get the logical NOT of that value. If that value was 0, null, or an empty string; the ! operator will result in 1; otherwise, it will be 0.

3) Compare that value to a brand new list. It will never be equal, because either 0 or 1 is being compared to a list.

So that code doesn't make sense, on several levels. That's the result of flailing. Somewhere along the way you got lost, and that's why you made a change to an if() statement that wasn't even mentioned. All you need to do is slow down and read back over the code changes I mentioned, and it should fall into place.