Godot Template: Enemy Drops¶
Overview¶
This bit of code determines what enemies drop and how often they drop it. It would be a good template for NPC conversations as well.
Exports¶
- ITEM_DROP_PERCENT
The chance of an enemy dropping something when they die
This is a percent and should be from 0-100
- ITEM_DROP_WEIGHT
Dictionary: the key is the scene path (-.tscn) to a pickup and the value is the weight of the pickup
Weights are not percentages, but simply relative to each other. An item with weight 4 has twice the likelihood of dropping as an item of weight 2.
Normalization¶
Because items are randomly chosen by adding them to a list and picking one, we need to make sure our list does not end up ridiculously long. Entity.normalize_item_drop_weights() tries to keep the total item weight under 100 and is run during Entity._ready()
- Sum all of the weights.
We cannot force a dictionary export to be an integer, so we need to round them.
This will fail if they are not at least numeric, we want it to.
If the sum is greater than 100, then set our multiplier so that the sum would be 100.
- For each value:
Multiply it by the multiplier
Round it, unless rounding it forces it to zero, in which case set it to 1.
Because of the rounding, our sum may end up being greater than 100, that’s not that important.
If it is important that you preserve initial weights for future adjustment (i.e. if single weights are adjusted in the code based on game-play) then you should make sure to do that somewhere. This process destroys the original list.
Enemy Death¶
When and entity of type EMEMY dies, it calls ‘Entity.enemy_drop()’_. This function determines what, if anything, they drop and instances the drop scene.
Get a random number between 0 and 99.
If it is strictly less that the drop percentage, then move on.
Go through all of the keys in ITEM_DROP_WEIGHTS. Add value number of copies key into drop_list.
Randomly select a key from drop_list and instance the scene.
Code¶
Entity.normalize_item_drop_weights()¶
func normalize_item_drop_weights():
var sum = 0
# force multiplier to be a float
var multiplier = 1.0
for key in ITEM_DROP_WEIGHTS:
sum += round(ITEM_DROP_WEIGHTS[key])
# if our sum is greater than 100 then we want then find the
# multiplier that will bring it close to 100
if sum > 100:
multiplier = 100/sum
for key in ITEM_DROP_WEIGHTS:
# First do the multiplier
ITEM_DROP_WEIGHTS[key] = multiplier * float(ITEM_DROP_WEIGHTS[key])
# if rounding it will make it zero (i.e. it was .4) then make it 1
if ITEM_DROP_WEIGHTS[key] > 0 && round(ITEM_DROP_WEIGHTS[key]) == 0:
ITEM_DROP_WEIGHTS[key] = 1
else:
ITEM_DROP_WEIGHTS[key] = round(ITEM_DROP_WEIGHTS[key])
Code¶
Entity.enemy_drop()¶
func enemy_drop():
# drop is a number between 0 and 99
var drop = randi() % 100
# if drop is strictly less than our percentage, then drop something
if drop < ITEM_DROP_PERCENT:
# Here we are basically filling a hat with names.
# For each key, we'll put [value] entries of the key into the list
var drop_list = []
for key in ITEM_DROP_WEIGHTS:
for i in range(ITEM_DROP_WEIGHTS[key]):
drop_list.append(key)
# index is a number between 0 and list size - 1
var index = randi() % drop_list.size()
# load the scene at index
var scene = str("res://", drop_list[index], ".tscn")
instance_scene(load(scene))