Fixing a CG Gallery unlock bug. Thumbnail of a Kahlua steamer with cocoa powder sprinkled on top.

CG Gallery unlock bug

The recent Android build/update also introduced a bug where CGs weren’t unlocking properly in the gallery. Some investigation into how images are indicated as being seen revealed that the new layeredimage syntax was not playing nicely.

Images are defined in the format of image_name attribute1 attribute2 .... Ren’Py keeps a dictionary of seen images in persistent._seen_images with key-value pairs of (image_name, attribute1, attribute2 …):Boolean, where the Boolean is True/False depending on whether the image has been seen.

Code for unlocking gallery images is simply gallery.unlock(image_name). Before the layeredimage optimization conversion, we were doing gallery.unlock('cg1') and the like. This worked out alright because the code for showing the image in-game was scene cg1 with Dissolve(.3). In both the gallery unlock code and the in-game code, the image being viewed is cg1. After the optimization update, we had to change in-game cg code to scene cg1 attribute1 attribute2 with Dissolve(.3).

We originally thought that Ren’Py was looking up whether just image_name was seen by the player, not image_name attribute1 attribute2 was seen by the player. An example (inefficient) code for this kind of lookup is:

image_definition = ('image_name', 'attribute1', 'attribute2')
image_seen = False
for key in persistent._seen_images.keys():
	if image_definition[0] in key:
		image_seen = True

Instead, Ren’Py is doing a very basic lookup.

image_definition = ('image_name', 'attribute1', 'attribute2')
image_seen = False
if image_definition in persistent.seen_images.keys():
	image_seen = True

So we needed to change the gallery unlock code to include all the image attributes: gallery.unlock('cg1 attribute1 attribute2'). And order matters. gallery.unlock('cg1 attribute2 attribute1') would not work because it’s a different tuple.

Base seems to be a special keyword for layeredimages

In one of our layeredimages, we had an attribute base.

layeredimage randal:
	always "something"
	group base prefix "base":
		attribute 1 "base1"
		attribute 2 "base2"
	group eyes prefix "eyes":
		attribute neutral ...

We expected that if we did scene randal base_1 eyes_neutral, then the corresponding tuple would be ('randal', 'base_1', 'eyes_neutral'). This was not the case. Instead, the tuple was ('randal', '1', 'eyes_neutral'). This caused a bit of trouble with figuring out why one of the CGs wasn’t unlocking properly. A quick fix was to change the prefix to “pose”.