append () an array inside dictionary spreads to other arrays

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Akuma

this code is acting weird , Game.target is a from 0 to 3
Game.Players is a dictionary that looks somethin like this

Players = {}

im merging in the content from another dictionary to generate 4 players data to look like this:

  export var Players= {
   "0" : {
	"HP" : 5,
	"Status_eff" : [],
	"Strength": 2
}  "1" : {
	"HP" : 5,
	"Status_eff" : [],
	"Strength": 2
 }
}

	Game.Players[Game.target].Status_eff.append("Poison")

it works for the most part but the append adds "Poison to all of the arrays
the damage and stuff works fine on the right target. but Status_eff is synced across all Players “0”, “1”, “2”, “3”
why is it acting like that, what can I do to fix it. Trying to make it systematic so I can build on it later

Arrays are passed by reference. When you generate the player data, are you using duplicate()? You might need to pass in a false.

exuin | 2022-12-11 06:34

hmm… im using merge() somethin like

var x = game.Players.size()
Game.Players.merge({ x : { } } )
Game.Players[x].merge(Game.Race.Goblin)

x to generate the 0: {}, 1: {} arrays
and the other one to copy properties

Akuma | 2022-12-11 08:15

worth mentioning is that I also randomize HP and other properties in the dictionary unique to each Player which works fine, but when i use append() to add values or use clear() it applies to all the inner dictionaries

Akuma | 2022-12-11 08:23

:bust_in_silhouette: Reply From: Gluon

Well you are missing a “,” in your dictionary above so I am not certain how you got it to work at all but the reason you wouldnt be able to append is you arent passing anything to the system to tell it to be specific to a given path.

Try the below as an example you will find it appends as you desire,

var Players= {
   "0" : {
	"HP" : 5,
	"Status_eff" : ["fire"],
	"Strength": 2},
  "1" : {
	"HP" : 5,
	"Status_eff" : ["water"],
	"Strength": 2
 }
}

func _ready():
	print(Players)
	print(Players["0"]["Status_eff"][0])
	Players["0"]["Status_eff"].append("Poison")
	print(Players)

so is the trick here to have something unique in the “Status_eff” array? because I can’t exactly apply that as its getting copied along the rest to auto generate the 4 players using merge()

onready var Runner = get_node("Runner")
signal raceOver

func _ready():
for i in 4-Game.Players.size():
	var Goblin = load("res://Scenes/Goblin.tscn").instance()
	Runner.add_child_below_node(Runner,Goblin)

im using this to generate the goblins based on the Game.Players.size()

these are the actual globals in Game.gd, I just typed an example earlier of how it should look when its filled

export var Players = {}


export var Race = {
"Goblin" : {
	"maxHP" : 5,
	"HP" : 5,
	"Speed" : 100,
	"maxSpeed" : 100,
	"Speedmlt" : 1,
	"Status_eff" : [],
	"Strength": 2,
	"Stopped" : true,
	"Hired" : false
}
}

inside the goblin/player scene im cloning there is the player.gd script generating the dictionaries

func _on_Goblin_tree_entered():
  var x = Game.Players.size()
 index = x
 Game.Players.merge({ x : { } } )
 Game.Players[x].merge(Game.Race.Goblin)
 name = str(index)
 var rng = RandomNumberGenerator.new()
 rng.randomize()
 Game.Players[index].HP = Game.Players[index].maxHP + rng.randi_range(-2,2)
 Game.Players[index].Speed = Game.Players[index].maxSpeed + rng.randi_range(-25,25)

I was trying to keep the post short and concise, but I’m not too sure where the issue lies still. can’t seem to fix it
I tried to generate the dictionaries inside the same script that generates the Goblin.tscn but results were the same

Akuma | 2022-12-11 09:05

You just need to specify which path to use. As it stands at the moment you are telling it to append all "Status_eff" dictionaries so it is recursively checking through the whole dictionary structure and appending poison to any Status_eff it finds. You need to specify which player’s Status_eff to update.

Gluon | 2022-12-11 09:11

Game.Players[Game.target].Status_eff.append("Poison")

thought im doin exactly that with this part
as game target is basically index to tell it, but its accessing all somehow

had to make a different dictionary with predefined arrays to get around it

Akuma | 2022-12-11 09:25

Okay well as I say the code at the top of my answer does what you want it to do so if you use this method it works but if you have a workaround solution you are happy with that is fine too.

Gluon | 2022-12-11 09:39

yeah i basically had to make something like

status_eff {
1:[],
2:[],
3:[],
4:[]
}

and use that instead and it worked, thank you for your help

Akuma | 2022-12-11 09:55

Okay, that would work I suppose but I would think it would be better to just use the method at the top and keep it as a nested dictionary? Have you tried the method I suggested? The line;

Players[PlayerNumber as string]["Status_eff"].append("Poison")

should do the job fine

Gluon | 2022-12-11 10:03