Bool being reset for some reason

Hi Everyone,

I’m hoping someone can help me see what is wrong with this code. This is a seed scene that randomly selects from a list to create different types of resource scenes.

That is working fine until I wanted to make it so it would add just 1 scene called ‘Castle’. So there is a bool for whether or not there has been a castle created. when the castle is create, that bool is being set to true (the #print shows it). However, when it goes back to pick and create the next scene, the bool is now false. So it is creating multiple castle scenes. Can anyone see what I am doing incorrectly here?

extends Area2D

enum ZoneType {CASTLE, WOOD, STONE, FOOD, VILLAGERS, WEAPONS, SOLDIERS, KEEPS}

var zone_type: ZoneType #= ZoneType.WOOD
var soldiers_in_zone: int = 0
var soldiers_moving_in: int = 0
var soldiers_moving_out: int = 0
var castle_soldiers: int = 50
var castle_created: bool = false

var friendly_color : Color = Color(0, 1, 0, 1) # Green
var neutral_color : Color = Color(1, 1, 0, 1) # Yellow
var enemy_color : Color = Color(1, 0, 0, 1) # Red

var Barracks = load("res://Assets/Barracks.png")
var Blacksmith = load("res://Assets/Blacksmith.png")
var Farm1 = load("res://Assets/Farm1.png")
var Farm2 = load("res://Assets/Farm2.png")
var Gatherer = load("res://Assets/Gatherer.png")
var Keep = load("res://Assets/Keep.png")
var Stone_Pile = load("res://Assets/Stone_Pile.png")
var Stone_Quary = load("res://Assets/Stone_Quarry.png")
var Timber_Mill = load("res://Assets/Timber_Mill.png")
var Townhall = load("res://Assets/Townhall.png")
var Training_Grounds = load("res://Assets/Training_Grounds.png")
var Village = load("res://Assets/Village.png")
var Wheat_Field = load("res://Assets/Wheat.png")
var Wood_Pile = load("res://Assets/Wood.png")
var Castle = load("res://Assets/Castle.png")

var zoneTypes = [ZoneType.CASTLE, ZoneType.WOOD, ZoneType.STONE, ZoneType.FOOD, ZoneType.VILLAGERS, ZoneType.WEAPONS, ZoneType.SOLDIERS, ZoneType.KEEPS]
# Maintain counters for each zone type
var zone_counters = {
	ZoneType.WOOD: 0,
	ZoneType.STONE: 0,
	ZoneType.FOOD: 0,
	ZoneType.VILLAGERS: 0,
	ZoneType.WEAPONS: 0,
	ZoneType.SOLDIERS: 0,
	ZoneType.KEEPS: 0,
	ZoneType.CASTLE: 1
}

var RNG = RandomNumberGenerator.new()

const ZONE_SIZE: int = 512
signal zone_clicked(zone)

func _ready():
	# Ensure different random sequence each time the game runs
	randomize()
	# Ensure that there is at least one of each zone type
	for type in zone_counters.keys():
		zone_counters[type] = 1
	
	# Pick a zone type based on the counters
	zone_type = pick_random_zone_type()
	
	# Ensure Castle is initialized once
	if zone_type == ZoneType.CASTLE and castle_created == false:
		castle_created = true
		soldiers_in_zone = 50  # Set initial soldiers in the Castle
		print("Castle created with 50 soldiers")
		zone_counters[ZoneType.CASTLE] = 0  # Set the count to 0 to avoid re-creation
	
	add_to_group("Zone_Click")
	update_status()
	set_zone_border()
	update_zone_sprite()

func _process(delta):
	$Soldiers_in_Zone.text = str(soldiers_in_zone-soldiers_moving_out)

###FIGURE OUT WHY CASTLE_CREATED IS NOT STAYING TRUE!!!

func pick_random_zone_type() -> ZoneType:
	var zoneTypes = [ZoneType.CASTLE, ZoneType.WOOD, ZoneType.STONE, ZoneType.FOOD, ZoneType.VILLAGERS, ZoneType.WEAPONS, ZoneType.SOLDIERS, ZoneType.KEEPS]
	print("Castle Status: ", castle_created)
	# If Castle is already created, remove it from the zoneTypes array
	if castle_created == true:
		zoneTypes.erase(ZoneType.CASTLE)
		print("Erased castle")
	
	# Calculate the total count of all zones
	var total_zones = 0
	
	for count in zone_counters.values():
		total_zones += count

	# Calculate weights inversely proportional to the counts
	var weights = []
	for type in zoneTypes:
		var weight = (total_zones - zone_counters[type]) + 1
		weights.append(weight)

	# Normalize the weights to get a probability distribution
	var weight_sum = sum(weights)
	var probabilities = []
	for weight in weights:
		probabilities.append(float(weight) / weight_sum)

	# Pick a random zone type based on the probabilities
	var random_value = randf()
	var cumulative_probability = 0.0
	for i in range(probabilities.size()):
		cumulative_probability += probabilities[i]
		if random_value <= cumulative_probability:
			return zoneTypes[i]
	
	var fallback_type = zoneTypes[randi() % zoneTypes.size()]
	print("Fallback zone type: ", fallback_type)
	return fallback_type

func sum(values):
	var total = 0
	for value in values:
		total += value
	return total

Thank you in advance.

First of all, please never write

if variable == true # use "if variable" instead
if variable == false # use "if not variable" instead

Now to answer your question:
Is your Area2D the exact same object or is it recreated with the new scene ?
If it is recreated with the next scene, then it will reinitialize.
To prevent that, you need to make sure the variable is either externalized (Resource, json, …) or in an Autoload.

perhaps a static observer class would help. If there’s only ever one castle, it could just be a simple static, but if there’s multiple then I think you’d want each castle to ‘check in’ with the observer, then when things want to know if castle_created is true, they ask the observer and pass it some unique castle ID. Then the observer would maintain it’s own dictionary or whatever of which castles are registered and what their status is. And when the castle actually is created, notify the observer of that.

1 Like

The zones are static. Any idea why the variable is resetting?

There doesn’t appear to be anything declared as static in your sample code. Is it in other code? To be clear when I mention ‘static’ I’m speaking of a specific kind of function you can declare, that has special properties and it’s own variable scope. If you’re unfamiliar with this I’d definitely suggest checking it out, they can be very helpful.

Ok, I did some googling of what those are and I do not have any. But I also don’t understand how that would help here.

it appears to me you are calling pick random zone type before ever setting castle to true. So your if castle_created == true would never return true.

You declared var castle_created: bool = false. Then set it to true. But if you change scene, or are reloading the current scene, it will reload the script too, setting to false again.
So there options: If you have a node that is the root with this script, and adding a scene like ‘Castle’ as a child, then removing when not need anymore, repeating the process, should work.
If you are changing scene, reloading scene that this script is attached, then you need another solution. Static could help, or make a autoload scene, a scene that is global and never resets.

ok, while typing out a greater explanation i had an epiphany… make the variable “global”.

In the main game scene I have put in a 4x4 grid of zone seeds. Each seeds it to randomly select a zone type that it will be. So what was happening is the script was running separately for each seed and looking for its own castle_status. I moved this to a global variable and now it is generating just 1 because all the seeds are now looking at the same variable.

Thank you everyone for your help.

1 Like