ID:1449346
 
(See the best response by Kaiochao.)
Code:
world
proc
BuildDatabase()
//This sets up the database for the entire world
BuffDatabase = new
world << "Building database..."

var/Buff/b

b = new
b.name = "Blessing of Cuddles"
b.hp_value = 30
b.duration = 100
b.icon = 'buffs.dmi'
b.icon_state = "buff template"
b.index = 1
BuffDatabase.entries[b.index] = b

----------My test "Database"-------

Database
var/list/entries[100]
/var/global/Database/Items/ItemDatabase
/var/global/Database/Buffs/BuffDatabase

Buffs
proc
GetBuff(index)
return entries[index]

---------Code that accesses the database and pulls the buff from the list via its index number. Yes, it works, except for one small thing...---

//Creates a buff based on the index number specified in the var named buff.
if (buff)
var/Buff/b = new //New buff
b = BuffDatabase.GetBuff(buff) //Pulls a buff from the database
b.source = m
b.loc = t
spawn() b.Apply_Buff(t) //Applies the buff


Problem description:

When I try to create another instance of the Buff object, it refers to the object in the list... but I thought it creates an entirely new copy! It didn't, so I wonder if there is a way to create a brand new copy of an instance.
Best response
You're setting b to a new /Buff.
var/Buff/b = new


Then you're setting b to a /Buff in the "entries" list.
b = BuffDatabase.GetBuff(buff)


The /Buff you created first is gone, since you don't have any references to it. I'm not sure why you're expecting your code to not do what it plainly says it does.


Object instances are created from type paths. There's currently no easy way to clone an existing instance, if that's what you're trying to do.
In response to Kaiochao
Kaiochao wrote:
You're setting b to a new /Buff.
> var/Buff/b = new
>

Then you're setting b to a /Buff in the "entries" list.
> b = BuffDatabase.GetBuff(buff)
>

The /Buff you created first is gone, since you don't have any references to it. I'm not sure why you're expecting your code to not do what it plainly says it does.


Object instances are created from type paths. There's currently no easy way to clone an existing instance, if that's what you're trying to do.

I am trying to clone an instance, actually. But if that's the case then I know I can handle that.

As for the creating a new buff, I guess I took the old saying "computers are sophisticated idiots" a bit too far. :Op
Cloning instances in a nutshell

var/list/L = (new /obj/obj1, new /obj/obj3)
var/obj/obj2clone = pick(L)
var/obj/newobj = new obj2clone.type


Well, I suppose it's not true cloning since the variables attached to obj2clone aren't passed. But I didn't know if that was the plan or not.
In response to Lugia319
I'm gonna say that copying over the variables was the plan, considering he's only using /Buff without child types. There are snippets for this around the forums.
Would it be possible to create a temporary savefile to store the instance's data, and load it into a new instance?
In response to Lugia319
I don't see why not, that's precisely what savefiles and Read()/Write() are for. They're used more for mobs, but they shouldn't work differently for any other datum.
In response to Kaiochao
Just a funny little tidbit... I remember why I always use something like var/Buff/b = new when working with anything that isn't a single value. For some reason, it just throws me a null exception for reasons I can't figure out.


            GetBuff(index)
var/Buff/a
var/Buff/b = new

a = entries[index] //set a to the list entry

//Copy, copy, copy!!!
b.name = a.name
b.desc = a.desc
b.duration = a.duration

b.hp_value = a.hp_value
b.mp_value = a.mp_value
b.attack_value = a.attack_value
b.defense_value = a.defense_value

return b


That code works perfectly, but if I just use var/Buff/b, it gives me

runtime error: Cannot modify null.name.
proc name: GetBuff (/Database/Buffs/proc/GetBuff)
usr: Wontoon (/mob/player)
src: /Database/Buffs (/Database/Buffs)
call stack:
/Database/Buffs (/Database/Buffs): GetBuff(1)
Blessing of Cuddles (/Skill): Execute(Wontoon (/mob/player), Wontoon (/mob/player))
Blessing of Cuddles (/Skill): Use()
runtime error: Cannot modify null.source.
proc name: Execute (/Skill/proc/Execute)
usr: Wontoon (/mob/player)
src: Blessing of Cuddles (/Skill)
call stack:
Blessing of Cuddles (/Skill): Execute(Wontoon (/mob/player), Wontoon (/mob/player))
Blessing of Cuddles (/Skill): Use()


So there's likely a little caveat I am not aware of.
In response to Wontoon
Creating a variable sets it to null unless you initialize it. The "new" creates a new instance of /Buff (the type of the variable it's initializing) and returns it to the variable "b".

If you just write "var/Buff/b" without setting it to anything, then b = null, which is why "b.name = a.name" is being read as "null.name = a.name".

It sounds like you're expecting DM to do something that it just doesn't do.
In response to Kaiochao
Kaiochao wrote:
Creating a variable sets it to null unless you initialize it. The "new" creates a new instance of /Buff (the type of the variable it's initializing) and returns it to the variable "b".

If you just write "var/Buff/b" without setting it to anything, then b = null, which is why "b.name = a.name" is being read as "null.name = a.name".

It sounds like you're expecting DM to do something that it just doesn't do.

Oh!
That clear things up for me. Was thinking that all of the vars and everything for that type was created when it was declared, and after the crashes I thought "new" was always needed. So in your example, new wasn't needed because it was being initialized to be entries[index].

I learn something new every day. :D